summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2021-08-24 16:00:38 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-08-24 16:00:38 +0000
commitaf8b4f4dc2e2c2dcaff4a6e8dea5bfd27bf2dc5a (patch)
tree904d4afcaf52cbf09958ff29488a07899e3ba289
parent7ec41085c0625e6e4d3ea4f3ffa8c8b2348f2a7e (diff)
parent8c500d588286605b1617a81547a8951aef7c8e9f (diff)
Merge "AudioSystem JNI: Add support for spatializer APIs" into sc-v2-dev am: 8c500d5882
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15557293 Change-Id: I32955fb8cdff488ed3cf1ec6a48f8f3173d05c91
-rw-r--r--Android.bp2
-rw-r--r--core/jni/Android.bp2
-rw-r--r--core/jni/android_media_AudioDeviceAttributes.cpp27
-rw-r--r--core/jni/android_media_AudioDeviceAttributes.h3
-rw-r--r--core/jni/android_media_AudioSystem.cpp84
-rw-r--r--media/java/android/media/AudioSystem.java41
6 files changed, 149 insertions, 10 deletions
diff --git a/Android.bp b/Android.bp
index be10428a19ce..956582b45929 100644
--- a/Android.bp
+++ b/Android.bp
@@ -342,6 +342,8 @@ java_defaults {
"modules-utils-preconditions",
"modules-utils-os",
"framework-permission-aidl-java",
+ "spatializer-aidl-java",
+ "audiopolicy-types-aidl-java",
],
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index f46aadfa3c3f..49066e35f859 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -243,6 +243,8 @@ cc_library_shared {
shared_libs: [
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
+ "audiopolicy-types-aidl-cpp",
+ "spatializer-aidl-cpp",
"av-types-aidl-cpp",
"android.hardware.camera.device@3.2",
"libandroidicu",
diff --git a/core/jni/android_media_AudioDeviceAttributes.cpp b/core/jni/android_media_AudioDeviceAttributes.cpp
index 2a16dce99125..6879a6008f5a 100644
--- a/core/jni/android_media_AudioDeviceAttributes.cpp
+++ b/core/jni/android_media_AudioDeviceAttributes.cpp
@@ -24,6 +24,11 @@ using namespace android;
static jclass gAudioDeviceAttributesClass;
static jmethodID gAudioDeviceAttributesCstor;
+static struct {
+ jfieldID mAddress;
+ jfieldID mNativeType;
+ // other fields unused by JNI
+} gAudioDeviceAttributesFields;
namespace android {
@@ -33,12 +38,25 @@ jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAtt
jint jNativeType = (jint)devTypeAddr->mType;
ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->getAddress()));
- *jAudioDeviceAttributes = env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor,
- jNativeType, jAddress.get());
+ *jAudioDeviceAttributes =
+ env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor,
+ jNativeType, jAddress.get());
return jStatus;
}
+jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr,
+ const jobject jAudioDeviceAttributes) {
+ devTypeAddr->mType = (audio_devices_t)env->GetIntField(jAudioDeviceAttributes,
+ gAudioDeviceAttributesFields.mNativeType);
+
+ jstring jAddress = (jstring)env->GetObjectField(jAudioDeviceAttributes,
+ gAudioDeviceAttributesFields.mAddress);
+ devTypeAddr->setAddress(ScopedUtfChars(env, jAddress).c_str());
+
+ return AUDIO_JAVA_SUCCESS;
+}
+
} // namespace android
int register_android_media_AudioDeviceAttributes(JNIEnv *env) {
@@ -48,5 +66,10 @@ int register_android_media_AudioDeviceAttributes(JNIEnv *env) {
gAudioDeviceAttributesCstor =
GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>", "(ILjava/lang/String;)V");
+ gAudioDeviceAttributesFields.mNativeType =
+ GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mNativeType", "I");
+ gAudioDeviceAttributesFields.mAddress =
+ GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mAddress", "Ljava/lang/String;");
+
return 0;
}
diff --git a/core/jni/android_media_AudioDeviceAttributes.h b/core/jni/android_media_AudioDeviceAttributes.h
index b49d9ba515b8..4a1f40d9bb7c 100644
--- a/core/jni/android_media_AudioDeviceAttributes.h
+++ b/core/jni/android_media_AudioDeviceAttributes.h
@@ -28,6 +28,9 @@ namespace android {
extern jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAttributes,
const AudioDeviceTypeAddr *devTypeAddr);
+
+extern jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr,
+ const jobject jAudioDeviceAttributes);
} // namespace android
#endif \ No newline at end of file
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 47db3547f931..509b7ad74a29 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -27,6 +27,8 @@
#include "core_jni_helpers.h"
#include <android/media/AudioVibratorInfo.h>
+#include <android/media/INativeSpatializerCallback.h>
+#include <android/media/ISpatializer.h>
#include <audiomanager/AudioManager.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
@@ -2023,6 +2025,18 @@ android_media_AudioSystem_registerRoutingCallback(JNIEnv *env, jobject thiz)
AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback);
}
+void javaAudioFormatToNativeAudioConfig(JNIEnv *env, audio_config_t *nConfig,
+ const jobject jFormat, bool isInput) {
+ *nConfig = AUDIO_CONFIG_INITIALIZER;
+ nConfig->format = audioFormatToNative(env->GetIntField(jFormat, gAudioFormatFields.mEncoding));
+ nConfig->sample_rate = env->GetIntField(jFormat, gAudioFormatFields.mSampleRate);
+ jint jChannelMask = env->GetIntField(jFormat, gAudioFormatFields.mChannelMask);
+ if (isInput) {
+ nConfig->channel_mask = inChannelMaskToNative(jChannelMask);
+ } else {
+ nConfig->channel_mask = outChannelMaskToNative(jChannelMask);
+ }
+}
static jint convertAudioMixToNative(JNIEnv *env,
AudioMix *nAudioMix,
@@ -2043,13 +2057,7 @@ static jint convertAudioMixToNative(JNIEnv *env,
nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
- nAudioMix->mFormat = AUDIO_CONFIG_INITIALIZER;
- nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
- gAudioFormatFields.mSampleRate);
- nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
- gAudioFormatFields.mChannelMask));
- nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat,
- gAudioFormatFields.mEncoding));
+ javaAudioFormatToNativeAudioConfig(env, &nAudioMix->mFormat, jFormat, false /*isInput*/);
env->DeleteLocalRef(jFormat);
jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
@@ -2712,6 +2720,58 @@ static jint android_media_AudioSystem_setVibratorInfos(JNIEnv *env, jobject thiz
return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
}
+static jobject android_media_AudioSystem_getSpatializer(JNIEnv *env, jobject thiz,
+ jobject jISpatializerCallback) {
+ sp<media::INativeSpatializerCallback> nISpatializerCallback
+ = interface_cast<media::INativeSpatializerCallback>(
+ ibinderForJavaObject(env, jISpatializerCallback));
+ sp<media::ISpatializer> nSpatializer;
+ status_t status = AudioSystem::getSpatializer(nISpatializerCallback,
+ &nSpatializer);
+ if (status != NO_ERROR) {
+ return nullptr;
+ }
+ return javaObjectForIBinder(env, IInterface::asBinder(nSpatializer));
+}
+
+static jboolean android_media_AudioSystem_canBeSpatialized(JNIEnv *env, jobject thiz,
+ jobject jaa, jobject jFormat,
+ jobjectArray jDeviceArray) {
+ JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return false;
+ }
+
+ AudioDeviceTypeAddrVector nDevices;
+
+ const size_t numDevices = env->GetArrayLength(jDeviceArray);
+ for (size_t i = 0; i < numDevices; ++i) {
+ AudioDeviceTypeAddr device;
+ jobject jDevice = env->GetObjectArrayElement(jDeviceArray, i);
+ if (jDevice == nullptr) {
+ return false;
+ }
+ jStatus = createAudioDeviceTypeAddrFromJava(env, &device, jDevice);
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return false;
+ }
+ nDevices.push_back(device);
+ }
+
+ audio_config_t nConfig;
+ javaAudioFormatToNativeAudioConfig(env, &nConfig, jFormat, false /*isInput*/);
+
+ bool canBeSpatialized;
+ status_t status =
+ AudioSystem::canBeSpatialized(paa.get(), &nConfig, nDevices, &canBeSpatialized);
+ if (status != NO_ERROR) {
+ ALOGW("%s native returned error %d", __func__, status);
+ return false;
+ }
+ return canBeSpatialized;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] =
@@ -2848,7 +2908,15 @@ static const JNINativeMethod gMethods[] =
(void *)android_media_AudioSystem_removeUserIdDeviceAffinities},
{"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid},
{"setVibratorInfos", "(Ljava/util/List;)I",
- (void *)android_media_AudioSystem_setVibratorInfos}};
+ (void *)android_media_AudioSystem_setVibratorInfos},
+ {"nativeGetSpatializer",
+ "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
+ (void *)android_media_AudioSystem_getSpatializer},
+ {"canBeSpatialized",
+ "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
+ "[Landroid/media/AudioDeviceAttributes;)Z",
+ (void *)android_media_AudioSystem_canBeSpatialized}};
+
static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 69d1889d5762..5d9f2909903b 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -18,6 +18,7 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.bluetooth.BluetoothCodecConfig;
@@ -2000,6 +2001,46 @@ public class AudioSystem
*/
public static native int setVibratorInfos(@NonNull List<Vibrator> vibrators);
+ /**
+ * @hide
+ * If a spatializer effect is present on the platform, this will return an
+ * ISpatializer interface to control this feature.
+ * If no spatializer is present, a null interface is returned.
+ * The INativeSpatializerCallback passed must not be null.
+ * Only one ISpatializer interface can exist at a given time. The native audio policy
+ * service will reject the request if an interface was already acquired and previous owner
+ * did not die or call ISpatializer.release().
+ * @param callback the callback to receive state updates if the ISpatializer
+ * interface is acquired.
+ * @return the ISpatializer interface made available to control the
+ * platform spatializer
+ */
+ @Nullable
+ public static ISpatializer getSpatializer(INativeSpatializerCallback callback) {
+ return ISpatializer.Stub.asInterface(nativeGetSpatializer(callback));
+ }
+ private static native IBinder nativeGetSpatializer(INativeSpatializerCallback callback);
+
+ /**
+ * @hide
+ * Queries if some kind of spatialization will be performed if the audio playback context
+ * described by the provided arguments is present.
+ * The context is made of:
+ * - The audio attributes describing the playback use case.
+ * - The audio configuration describing the audio format, channels, sampling rate ...
+ * - The devices describing the sink audio device selected for playback.
+ * All arguments are optional and only the specified arguments are used to match against
+ * supported criteria. For instance, supplying no argument will tell if spatialization is
+ * supported or not in general.
+ * @param attributes audio attributes describing the playback use case
+ * @param format audio configuration describing the audio format, channels, sampling rate...
+ * @param devices the sink audio device selected for playback
+ * @return true if spatialization is enabled for this context, false otherwise.
+ */
+ public static native boolean canBeSpatialized(AudioAttributes attributes,
+ AudioFormat format,
+ AudioDeviceAttributes[] devices);
+
// Items shared with audio service
/**