summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2014-05-19 19:02:51 -0700
committerEric Laurent <elaurent@google.com>2014-05-30 17:12:48 -0700
commitb69681c894c663e84f2826d9b0c832ceb9b45047 (patch)
treeca8396318b56f53719b61d93847aed0f8f958c06 /core
parent575510c48f3cad55a4751db89dc44e330b0cc9df (diff)
downloadframeworks_base-b69681c894c663e84f2826d9b0c832ceb9b45047.zip
frameworks_base-b69681c894c663e84f2826d9b0c832ceb9b45047.tar.gz
frameworks_base-b69681c894c663e84f2826d9b0c832ceb9b45047.tar.bz2
AudioSystem: added JNI for routing extensions
Bug: 14815883. Change-Id: Ia0c0d14a8e3051a4bc0ce502b6e979135b170c97
Diffstat (limited to 'core')
-rw-r--r--core/jni/android_media_AudioFormat.h54
-rw-r--r--core/jni/android_media_AudioSystem.cpp954
2 files changed, 1007 insertions, 1 deletions
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index fedb1b2..a2b1ed9 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -23,6 +23,11 @@
#define ENCODING_PCM_16BIT 2
#define ENCODING_PCM_8BIT 3
#define ENCODING_PCM_FLOAT 4
+#define ENCODING_INVALID 0
+#define ENCODING_DEFAULT 1
+
+#define CHANNEL_INVALID 0
+#define CHANNEL_OUT_DEFAULT 1
static inline audio_format_t audioFormatToNative(int audioFormat)
{
@@ -33,9 +38,58 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_PCM_8_BIT;
case ENCODING_PCM_FLOAT:
return AUDIO_FORMAT_PCM_FLOAT;
+ case ENCODING_DEFAULT:
+ return AUDIO_FORMAT_DEFAULT;
default:
return AUDIO_FORMAT_INVALID;
}
}
+static inline int audioFormatFromNative(audio_format_t nativeFormat)
+{
+ switch (nativeFormat) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return ENCODING_PCM_16BIT;
+ case AUDIO_FORMAT_PCM_8_BIT:
+ return ENCODING_PCM_8BIT;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return ENCODING_PCM_FLOAT;
+ case AUDIO_FORMAT_DEFAULT:
+ return ENCODING_DEFAULT;
+ default:
+ return ENCODING_INVALID;
+ }
+}
+
+static inline audio_channel_mask_t outChannelMaskToNative(int channelMask)
+{
+ switch (channelMask) {
+ case CHANNEL_OUT_DEFAULT:
+ case CHANNEL_INVALID:
+ return AUDIO_CHANNEL_NONE;
+ default:
+ return (audio_channel_mask_t)(channelMask>>2);
+ }
+}
+
+static inline int outChannelMaskFromNative(audio_channel_mask_t nativeMask)
+{
+ switch (nativeMask) {
+ case AUDIO_CHANNEL_NONE:
+ return CHANNEL_OUT_DEFAULT;
+ default:
+ return (int)nativeMask<<2;
+ }
+}
+
+static inline audio_channel_mask_t inChannelMaskToNative(int channelMask)
+{
+ return (audio_channel_mask_t)channelMask;
+}
+
+static inline int inChannelMaskFromNative(audio_channel_mask_t nativeMask)
+{
+ return (int)nativeMask;
+}
+
#endif // ANDROID_MEDIA_AUDIOFORMAT_H
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a9a62f8..b6e450d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -15,7 +15,7 @@
** limitations under the License.
*/
-#define LOG_TAG "AudioSystem"
+#define LOG_TAG "AudioSystem-JNI"
#include <utils/Log.h>
#include <jni.h>
@@ -26,6 +26,8 @@
#include <system/audio.h>
#include <system/audio_policy.h>
+#include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
// ----------------------------------------------------------------------------
@@ -33,12 +35,79 @@ using namespace android;
static const char* const kClassPathName = "android/media/AudioSystem";
+static jclass gArrayListClass;
+static struct {
+ jmethodID add;
+} gArrayListMethods;
+
+static jclass gAudioHandleClass;
+static jmethodID gAudioHandleCstor;
+static struct {
+ jfieldID mId;
+} gAudioHandleFields;
+
+static jclass gAudioPortClass;
+static jmethodID gAudioPortCstor;
+static struct {
+ jfieldID mHandle;
+ jfieldID mRole;
+ jfieldID mGains;
+ jfieldID mActiveConfig;
+ // other fields unused by JNI
+} gAudioPortFields;
+
+static jclass gAudioPortConfigClass;
+static jmethodID gAudioPortConfigCstor;
+static struct {
+ jfieldID mPort;
+ jfieldID mSamplingRate;
+ jfieldID mChannelMask;
+ jfieldID mFormat;
+ jfieldID mGain;
+} gAudioPortConfigFields;
+
+static jclass gAudioDevicePortClass;
+static jmethodID gAudioDevicePortCstor;
+
+static jclass gAudioDevicePortConfigClass;
+static jmethodID gAudioDevicePortConfigCstor;
+
+static jclass gAudioMixPortClass;
+static jmethodID gAudioMixPortCstor;
+
+static jclass gAudioMixPortConfigClass;
+static jmethodID gAudioMixPortConfigCstor;
+
+static jclass gAudioGainClass;
+static jmethodID gAudioGainCstor;
+
+static jclass gAudioGainConfigClass;
+static jmethodID gAudioGainConfigCstor;
+static struct {
+ jfieldID mIndex;
+ jfieldID mMode;
+ jfieldID mChannelMask;
+ jfieldID mValues;
+ jfieldID mRampDurationMs;
+ // other fields unused by JNI
+} gAudioGainConfigFields;
+
+static jclass gAudioPatchClass;
+static jmethodID gAudioPatchCstor;
+static struct {
+ jfieldID mHandle;
+ // other fields unused by JNI
+} gAudioPatchFields;
+
+
enum AudioError {
kAudioStatusOk = 0,
kAudioStatusError = 1,
kAudioStatusMediaServerDied = 100
};
+#define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
+
static int check_AudioSystem_Command(status_t status)
{
switch (status) {
@@ -281,6 +350,801 @@ android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
}
+
+static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
+{
+ return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
+ ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
+}
+
+static jint convertAudioPortConfigToNative(JNIEnv *env,
+ struct audio_port_config *nAudioPortConfig,
+ const jobject jAudioPortConfig)
+{
+ jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
+ jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
+ nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
+ nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
+ gAudioPortFields.mRole);
+ if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
+ nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
+ } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
+ nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
+ } else {
+ env->DeleteLocalRef(jAudioPort);
+ env->DeleteLocalRef(jHandle);
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
+ nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
+
+ nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
+ gAudioPortConfigFields.mSamplingRate);
+
+ bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
+ audio_channel_mask_t nMask;
+ jint jMask = env->GetIntField(jAudioPortConfig,
+ gAudioPortConfigFields.mChannelMask);
+ if (useInMask) {
+ nMask = inChannelMaskToNative(jMask);
+ ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
+ } else {
+ nMask = outChannelMaskToNative(jMask);
+ ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
+ }
+ nAudioPortConfig->channel_mask = nMask;
+
+ jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
+ audio_format_t nFormat = audioFormatToNative(jFormat);
+ ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
+ nAudioPortConfig->format = nFormat;
+ jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
+ if (jGain != NULL) {
+ nAudioPortConfig->gain.index = env->GetIntField(jGain, gAudioGainConfigFields.mIndex);
+ nAudioPortConfig->gain.mode = env->GetIntField(jGain, gAudioGainConfigFields.mMode);
+ ALOGV("convertAudioPortConfigToNative got gain index %d", nAudioPortConfig->gain.index);
+ jMask = env->GetIntField(jGain, gAudioGainConfigFields.mChannelMask);
+ if (useInMask) {
+ nMask = inChannelMaskToNative(jMask);
+ ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
+ } else {
+ nMask = outChannelMaskToNative(jMask);
+ ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
+ }
+
+ nAudioPortConfig->gain.channel_mask = nMask;
+ nAudioPortConfig->gain.ramp_duration_ms = env->GetIntField(jGain,
+ gAudioGainConfigFields.mRampDurationMs);
+
+ jintArray jValues = (jintArray)env->GetObjectField(jGain, gAudioGainConfigFields.mValues);
+ int *values = env->GetIntArrayElements(jValues, NULL);
+ size_t size = env->GetArrayLength(jValues);
+ memcpy(nAudioPortConfig->gain.values, values, size * sizeof(int));
+ env->DeleteLocalRef(jValues);
+ env->DeleteLocalRef(jGain);
+ } else {
+ ALOGV("convertAudioPortConfigToNative no gain");
+ nAudioPortConfig->gain.index = -1;
+ }
+ env->DeleteLocalRef(jAudioPort);
+ env->DeleteLocalRef(jHandle);
+ return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+static jint convertAudioPortConfigFromNative(JNIEnv *env,
+ jobject jAudioPort,
+ jobject *jAudioPortConfig,
+ const struct audio_port_config *nAudioPortConfig)
+{
+ jint jStatus = AUDIO_JAVA_SUCCESS;
+ jobject jAudioGainConfig = NULL;
+ jobject jAudioGain = NULL;
+ jintArray jGainValues;
+ bool audioportCreated = false;
+
+ ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
+
+ if (jAudioPort == NULL) {
+ jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
+ nAudioPortConfig->id);
+
+ ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
+ nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
+
+ if (jHandle == NULL) {
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ // create dummy port and port config objects with just the correct handle
+ // and configuration data. The actual AudioPortConfig objects will be
+ // constructed by java code with correct class type (device, mix etc...)
+ // and reference to AudioPort instance in this client
+ jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
+ jHandle,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ env->DeleteLocalRef(jHandle);
+ if (jAudioPort == NULL) {
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
+ nAudioPortConfig->id);
+
+ audioportCreated = true;
+ }
+
+ bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
+
+ audio_channel_mask_t nMask;
+ jint jMask;
+
+ int gainIndex = nAudioPortConfig->gain.index;
+ if (gainIndex >= 0) {
+ ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
+ gainIndex, nAudioPortConfig->gain.mode);
+ if (audioportCreated) {
+ ALOGV("convertAudioPortConfigFromNative creating gain");
+ jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
+ gainIndex,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0);
+ if (jAudioGain == NULL) {
+ ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ } else {
+ ALOGV("convertAudioPortConfigFromNative reading gain from port");
+ jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
+ gAudioPortFields.mGains);
+ if (jGains == NULL) {
+ ALOGV("convertAudioPortConfigFromNative could not get gains from port");
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
+ env->DeleteLocalRef(jGains);
+ if (jAudioGain == NULL) {
+ ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ }
+ //TODO: replace popcount by audio utils function mask to count
+ int numValues = popcount(nAudioPortConfig->gain.channel_mask);
+ jGainValues = env->NewIntArray(numValues);
+ if (jGainValues == NULL) {
+ ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ env->SetIntArrayRegion(jGainValues, 0, numValues,
+ nAudioPortConfig->gain.values);
+
+ nMask = nAudioPortConfig->gain.channel_mask;
+ if (useInMask) {
+ jMask = inChannelMaskFromNative(nMask);
+ ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
+ } else {
+ jMask = outChannelMaskFromNative(nMask);
+ ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
+ }
+
+ jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
+ gAudioGainConfigCstor,
+ gainIndex,
+ jAudioGain,
+ nAudioPortConfig->gain.mode,
+ jMask,
+ jGainValues,
+ nAudioPortConfig->gain.ramp_duration_ms);
+ env->DeleteLocalRef(jGainValues);
+ if (jAudioGainConfig == NULL) {
+ ALOGV("convertAudioPortConfigFromNative could not create gain config");
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ }
+ jclass clazz;
+ jmethodID methodID;
+ if (audioportCreated) {
+ clazz = gAudioPortConfigClass;
+ methodID = gAudioPortConfigCstor;
+ ALOGV("convertAudioPortConfigFromNative building a generic port config");
+ } else {
+ if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
+ clazz = gAudioDevicePortConfigClass;
+ methodID = gAudioDevicePortConfigCstor;
+ ALOGV("convertAudioPortConfigFromNative building a device config");
+ } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
+ clazz = gAudioMixPortConfigClass;
+ methodID = gAudioMixPortConfigCstor;
+ ALOGV("convertAudioPortConfigFromNative building a mix config");
+ } else {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ }
+ nMask = nAudioPortConfig->channel_mask;
+ if (useInMask) {
+ jMask = inChannelMaskFromNative(nMask);
+ ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
+ } else {
+ jMask = outChannelMaskFromNative(nMask);
+ ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
+ }
+
+ *jAudioPortConfig = env->NewObject(clazz, methodID,
+ jAudioPort,
+ nAudioPortConfig->sample_rate,
+ jMask,
+ audioFormatFromNative(nAudioPortConfig->format),
+ jAudioGainConfig);
+ if (*jAudioPortConfig == NULL) {
+ ALOGV("convertAudioPortConfigFromNative could not create new port config");
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ } else {
+ ALOGV("convertAudioPortConfigFromNative OK");
+ }
+
+exit:
+ if (audioportCreated) {
+ env->DeleteLocalRef(jAudioPort);
+ if (jAudioGain != NULL) {
+ env->DeleteLocalRef(jAudioGain);
+ }
+ }
+ if (jAudioGainConfig != NULL) {
+ env->DeleteLocalRef(jAudioGainConfig);
+ }
+ return jStatus;
+}
+
+
+static jint convertAudioPortFromNative(JNIEnv *env,
+ jobject *jAudioPort, const struct audio_port *nAudioPort)
+{
+ jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
+ jintArray jSamplingRates = NULL;
+ jintArray jChannelMasks = NULL;
+ jintArray jFormats = NULL;
+ jobjectArray jGains = NULL;
+ jobject jHandle = NULL;
+ bool useInMask;
+
+ ALOGV("convertAudioPortFromNative id %d role %d type %d",
+ nAudioPort->id, nAudioPort->role, nAudioPort->type);
+
+ jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
+ if (jSamplingRates == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ if (nAudioPort->num_sample_rates) {
+ env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
+ (jint *)nAudioPort->sample_rates);
+ }
+
+ jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks);
+ if (jChannelMasks == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
+
+ jint jMask;
+ for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) {
+ if (useInMask) {
+ jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]);
+ } else {
+ jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]);
+ }
+ env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask);
+ }
+
+ jFormats = env->NewIntArray(nAudioPort->num_formats);
+ if (jFormats == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ for (size_t j = 0; j < nAudioPort->num_formats; j++) {
+ jint jFormat = audioFormatFromNative(nAudioPort->formats[j]);
+ env->SetIntArrayRegion(jFormats, j, 1, &jFormat);
+ }
+
+ jGains = env->NewObjectArray(nAudioPort->num_gains,
+ gAudioGainClass, NULL);
+ if (jGains == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ for (size_t j = 0; j < nAudioPort->num_gains; j++) {
+ audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
+ if (useInMask) {
+ jMask = inChannelMaskFromNative(nMask);
+ ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
+ } else {
+ jMask = outChannelMaskFromNative(nMask);
+ ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
+ }
+
+ jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
+ j,
+ nAudioPort->gains[j].mode,
+ jMask,
+ nAudioPort->gains[j].min_value,
+ nAudioPort->gains[j].max_value,
+ nAudioPort->gains[j].default_value,
+ nAudioPort->gains[j].step_value,
+ nAudioPort->gains[j].min_ramp_ms,
+ nAudioPort->gains[j].max_ramp_ms);
+ if (jGain == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ env->SetObjectArrayElement(jGains, j, jGain);
+ env->DeleteLocalRef(jGain);
+ }
+
+ jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
+ nAudioPort->id);
+ if (jHandle == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+
+ if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
+ ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
+ jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
+ *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
+ jHandle, jSamplingRates, jChannelMasks, jFormats, jGains,
+ nAudioPort->ext.device.type, jAddress);
+ env->DeleteLocalRef(jAddress);
+ } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
+ ALOGV("convertAudioPortFromNative is a mix");
+ *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
+ jHandle, nAudioPort->role, jSamplingRates, jChannelMasks,
+ jFormats, jGains);
+ } else {
+ ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ if (*jAudioPort == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+
+ jobject jAudioPortConfig;
+ jStatus = convertAudioPortConfigFromNative(env,
+ *jAudioPort,
+ &jAudioPortConfig,
+ &nAudioPort->active_config);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+
+ env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
+
+exit:
+ if (jSamplingRates != NULL) {
+ env->DeleteLocalRef(jSamplingRates);
+ }
+ if (jChannelMasks != NULL) {
+ env->DeleteLocalRef(jChannelMasks);
+ }
+ if (jFormats != NULL) {
+ env->DeleteLocalRef(jFormats);
+ }
+ if (jGains != NULL) {
+ env->DeleteLocalRef(jGains);
+ }
+ if (jHandle != NULL) {
+ env->DeleteLocalRef(jHandle);
+ }
+
+ return jStatus;
+}
+
+
+static jint
+android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
+ jobject jPorts, jintArray jGeneration)
+{
+ ALOGV("listAudioPorts");
+
+ if (jPorts == NULL) {
+ ALOGE("listAudioPorts NULL AudioPort ArrayList");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
+ ALOGE("listAudioPorts not an arraylist");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ status_t status;
+ unsigned int generation1;
+ unsigned int generation;
+ unsigned int numPorts;
+ jint *nGeneration;
+ struct audio_port *nPorts = NULL;
+ int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
+
+ // get the port count and all the ports until they both return the same generation
+ do {
+ if (attempts-- < 0) {
+ status = TIMED_OUT;
+ break;
+ }
+
+ numPorts = 0;
+ status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
+ AUDIO_PORT_TYPE_NONE,
+ &numPorts,
+ NULL,
+ &generation1);
+ if (status != NO_ERROR || numPorts == 0) {
+ ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
+ break;
+ }
+ nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
+
+ status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
+ AUDIO_PORT_TYPE_NONE,
+ &numPorts,
+ nPorts,
+ &generation);
+ ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
+ numPorts, generation, generation1);
+ } while (generation1 != generation && status == NO_ERROR);
+
+ jint jStatus = nativeToJavaStatus(status);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+
+ nGeneration = env->GetIntArrayElements(jGeneration, NULL);
+ if (nGeneration == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ nGeneration[0] = generation1;
+ env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
+
+ for (size_t i = 0; i < numPorts; i++) {
+ jobject jAudioPort;
+ jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+ env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
+ }
+
+exit:
+ free(nPorts);
+ return jStatus;
+}
+
+static int
+android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
+ jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
+{
+ status_t status;
+ jint jStatus;
+
+ ALOGV("createAudioPatch");
+ if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ if (env->GetArrayLength(jPatches) != 1) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ jint numSources = env->GetArrayLength(jSources);
+ if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ jint numSinks = env->GetArrayLength(jSinks);
+ if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ audio_patch_handle_t handle = (audio_patch_handle_t)0;
+ jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
+ jobject jPatchHandle = NULL;
+ if (jPatch != NULL) {
+ if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
+ handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
+ }
+
+ struct audio_patch nPatch;
+
+ nPatch.id = handle;
+ nPatch.num_sources = 0;
+ nPatch.num_sinks = 0;
+ jobject jSource = NULL;
+ jobject jSink = NULL;
+
+ for (jint i = 0; i < numSources; i++) {
+ jSource = env->GetObjectArrayElement(jSources, i);
+ if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
+ jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
+ goto exit;
+ }
+ jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource);
+ env->DeleteLocalRef(jSource);
+ jSource = NULL;
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+ nPatch.num_sources++;
+ }
+
+ for (jint i = 0; i < numSinks; i++) {
+ jSink = env->GetObjectArrayElement(jSinks, i);
+ if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
+ jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
+ goto exit;
+ }
+ jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink);
+ env->DeleteLocalRef(jSink);
+ jSink = NULL;
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+ nPatch.num_sinks++;
+ }
+
+ ALOGV("AudioSystem::createAudioPatch");
+ status = AudioSystem::createAudioPatch(&nPatch, &handle);
+ ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
+
+ jStatus = nativeToJavaStatus(status);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+
+ if (jPatchHandle == NULL) {
+ jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
+ handle);
+ if (jPatchHandle == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
+ if (jPatch == NULL) {
+ jStatus = (jint)AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ env->SetObjectArrayElement(jPatches, 0, jPatch);
+ } else {
+ env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
+ }
+
+exit:
+ if (jPatchHandle != NULL) {
+ env->DeleteLocalRef(jPatchHandle);
+ }
+ if (jPatch != NULL) {
+ env->DeleteLocalRef(jPatch);
+ }
+ if (jSource != NULL) {
+ env->DeleteLocalRef(jSource);
+ }
+ if (jSink != NULL) {
+ env->DeleteLocalRef(jSink);
+ }
+ return jStatus;
+}
+
+static int
+android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
+ jobject jPatch)
+{
+ ALOGV("releaseAudioPatch");
+ if (jPatch == NULL) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ audio_patch_handle_t handle = (audio_patch_handle_t)0;
+ jobject jPatchHandle = NULL;
+ if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
+ handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
+ env->DeleteLocalRef(jPatchHandle);
+
+ ALOGV("AudioSystem::releaseAudioPatch");
+ status_t status = AudioSystem::releaseAudioPatch(handle);
+ ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
+ jint jStatus = nativeToJavaStatus(status);
+ return status;
+}
+
+static jint
+android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
+ jobject jPatches, jintArray jGeneration)
+{
+ ALOGV("listAudioPatches");
+ if (jPatches == NULL) {
+ ALOGE("listAudioPatches NULL AudioPatch ArrayList");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
+ ALOGE("listAudioPatches not an arraylist");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ status_t status;
+ unsigned int generation1;
+ unsigned int generation;
+ unsigned int numPatches;
+ jint *nGeneration;
+ struct audio_patch *nPatches = NULL;
+ jobjectArray jSources = NULL;
+ jobject jSource = NULL;
+ jobjectArray jSinks = NULL;
+ jobject jSink = NULL;
+ jobject jPatch = NULL;
+ int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
+
+ // get the patch count and all the patches until they both return the same generation
+ do {
+ if (attempts-- < 0) {
+ status = TIMED_OUT;
+ break;
+ }
+
+ numPatches = 0;
+ status = AudioSystem::listAudioPatches(&numPatches,
+ NULL,
+ &generation1);
+ if (status != NO_ERROR || numPatches == 0) {
+ ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
+ status);
+ break;
+ }
+ nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
+
+ status = AudioSystem::listAudioPatches(&numPatches,
+ nPatches,
+ &generation);
+ ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
+ numPatches, generation, generation1);
+
+ } while (generation1 != generation && status == NO_ERROR);
+
+ jint jStatus = nativeToJavaStatus(status);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+
+ nGeneration = env->GetIntArrayElements(jGeneration, NULL);
+ if (nGeneration == NULL) {
+ jStatus = AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ nGeneration[0] = generation1;
+ env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
+
+ for (size_t i = 0; i < numPatches; i++) {
+ jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
+ nPatches[i].id);
+ if (patchHandle == NULL) {
+ jStatus = AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ ALOGV("listAudioPatches patch %d num_sources %d num_sinks %d",
+ i, nPatches[i].num_sources, nPatches[i].num_sinks);
+
+ env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
+
+ // load sources
+ jSources = env->NewObjectArray(nPatches[i].num_sources,
+ gAudioPortConfigClass, NULL);
+ if (jSources == NULL) {
+ jStatus = AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+
+ for (size_t j = 0; j < nPatches[i].num_sources; j++) {
+ jStatus = convertAudioPortConfigFromNative(env,
+ NULL,
+ &jSource,
+ &nPatches[i].sources[j]);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+ env->SetObjectArrayElement(jSources, j, jSource);
+ env->DeleteLocalRef(jSource);
+ jSource = NULL;
+ ALOGV("listAudioPatches patch %d source %d is a %s handle %d",
+ i, j,
+ nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
+ nPatches[i].sources[j].id);
+ }
+ // load sinks
+ jSinks = env->NewObjectArray(nPatches[i].num_sinks,
+ gAudioPortConfigClass, NULL);
+ if (jSinks == NULL) {
+ jStatus = AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+
+ for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
+ jStatus = convertAudioPortConfigFromNative(env,
+ NULL,
+ &jSink,
+ &nPatches[i].sinks[j]);
+
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ goto exit;
+ }
+ env->SetObjectArrayElement(jSinks, j, jSink);
+ env->DeleteLocalRef(jSink);
+ jSink = NULL;
+ ALOGV("listAudioPatches patch %d sink %d is a %s handle %d",
+ i, j,
+ nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
+ nPatches[i].sinks[j].id);
+ }
+
+ jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
+ patchHandle, jSources, jSinks);
+ env->DeleteLocalRef(jSources);
+ jSources = NULL;
+ env->DeleteLocalRef(jSinks);
+ jSinks = NULL;
+ if (jPatch == NULL) {
+ jStatus = AUDIO_JAVA_ERROR;
+ goto exit;
+ }
+ env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
+ env->DeleteLocalRef(jPatch);
+ jPatch = NULL;
+ }
+
+exit:
+ if (jSources != NULL) {
+ env->DeleteLocalRef(jSources);
+ }
+ if (jSource != NULL) {
+ env->DeleteLocalRef(jSource);
+ }
+ if (jSinks != NULL) {
+ env->DeleteLocalRef(jSinks);
+ }
+ if (jSink != NULL) {
+ env->DeleteLocalRef(jSink);
+ }
+ if (jPatch != NULL) {
+ env->DeleteLocalRef(jPatch);
+ }
+ free(nPatches);
+ return jStatus;
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -309,10 +1173,98 @@ static JNINativeMethod gMethods[] = {
{"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency},
{"setLowRamDevice", "(Z)I", (void *)android_media_AudioSystem_setLowRamDevice},
{"checkAudioFlinger", "()I", (void *)android_media_AudioSystem_checkAudioFlinger},
+ {"listAudioPorts", "(Ljava/util/ArrayList;[I)I",
+ (void *)android_media_AudioSystem_listAudioPorts},
+ {"createAudioPatch", "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
+ (void *)android_media_AudioSystem_createAudioPatch},
+ {"releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
+ (void *)android_media_AudioSystem_releaseAudioPatch},
+ {"listAudioPatches", "(Ljava/util/ArrayList;[I)I",
+ (void *)android_media_AudioSystem_listAudioPatches},
};
+
int register_android_media_AudioSystem(JNIEnv *env)
{
+
+ jclass arrayListClass = env->FindClass("java/util/ArrayList");
+ gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
+ gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
+
+ jclass audioHandleClass = env->FindClass("android/media/AudioHandle");
+ gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
+ gAudioHandleCstor = env->GetMethodID(audioHandleClass, "<init>", "(I)V");
+ gAudioHandleFields.mId = env->GetFieldID(audioHandleClass, "mId", "I");
+
+ jclass audioPortClass = env->FindClass("android/media/AudioPort");
+ gAudioPortClass = (jclass) env->NewGlobalRef(audioPortClass);
+ gAudioPortCstor = env->GetMethodID(audioPortClass, "<init>",
+ "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
+ gAudioPortFields.mHandle = env->GetFieldID(audioPortClass, "mHandle",
+ "Landroid/media/AudioHandle;");
+ gAudioPortFields.mRole = env->GetFieldID(audioPortClass, "mRole", "I");
+ gAudioPortFields.mGains = env->GetFieldID(audioPortClass, "mGains",
+ "[Landroid/media/AudioGain;");
+ gAudioPortFields.mActiveConfig = env->GetFieldID(audioPortClass, "mActiveConfig",
+ "Landroid/media/AudioPortConfig;");
+
+ jclass audioPortConfigClass = env->FindClass("android/media/AudioPortConfig");
+ gAudioPortConfigClass = (jclass) env->NewGlobalRef(audioPortConfigClass);
+ gAudioPortConfigCstor = env->GetMethodID(audioPortConfigClass, "<init>",
+ "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
+ gAudioPortConfigFields.mPort = env->GetFieldID(audioPortConfigClass, "mPort",
+ "Landroid/media/AudioPort;");
+ gAudioPortConfigFields.mSamplingRate = env->GetFieldID(audioPortConfigClass,
+ "mSamplingRate", "I");
+ gAudioPortConfigFields.mChannelMask = env->GetFieldID(audioPortConfigClass,
+ "mChannelMask", "I");
+ gAudioPortConfigFields.mFormat = env->GetFieldID(audioPortConfigClass, "mFormat", "I");
+ gAudioPortConfigFields.mGain = env->GetFieldID(audioPortConfigClass, "mGain",
+ "Landroid/media/AudioGainConfig;");
+
+ jclass audioDevicePortConfigClass = env->FindClass("android/media/AudioDevicePortConfig");
+ gAudioDevicePortConfigClass = (jclass) env->NewGlobalRef(audioDevicePortConfigClass);
+ gAudioDevicePortConfigCstor = env->GetMethodID(audioDevicePortConfigClass, "<init>",
+ "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
+
+ jclass audioMixPortConfigClass = env->FindClass("android/media/AudioMixPortConfig");
+ gAudioMixPortConfigClass = (jclass) env->NewGlobalRef(audioMixPortConfigClass);
+ gAudioMixPortConfigCstor = env->GetMethodID(audioMixPortConfigClass, "<init>",
+ "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
+
+ jclass audioDevicePortClass = env->FindClass("android/media/AudioDevicePort");
+ gAudioDevicePortClass = (jclass) env->NewGlobalRef(audioDevicePortClass);
+ gAudioDevicePortCstor = env->GetMethodID(audioDevicePortClass, "<init>",
+ "(Landroid/media/AudioHandle;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+
+ jclass audioMixPortClass = env->FindClass("android/media/AudioMixPort");
+ gAudioMixPortClass = (jclass) env->NewGlobalRef(audioMixPortClass);
+ gAudioMixPortCstor = env->GetMethodID(audioMixPortClass, "<init>",
+ "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
+
+ jclass audioGainClass = env->FindClass("android/media/AudioGain");
+ gAudioGainClass = (jclass) env->NewGlobalRef(audioGainClass);
+ gAudioGainCstor = env->GetMethodID(audioGainClass, "<init>", "(IIIIIIIII)V");
+
+ jclass audioGainConfigClass = env->FindClass("android/media/AudioGainConfig");
+ gAudioGainConfigClass = (jclass) env->NewGlobalRef(audioGainConfigClass);
+ gAudioGainConfigCstor = env->GetMethodID(audioGainConfigClass, "<init>",
+ "(ILandroid/media/AudioGain;II[II)V");
+ gAudioGainConfigFields.mIndex = env->GetFieldID(gAudioGainConfigClass, "mIndex", "I");
+ gAudioGainConfigFields.mMode = env->GetFieldID(audioGainConfigClass, "mMode", "I");
+ gAudioGainConfigFields.mChannelMask = env->GetFieldID(audioGainConfigClass, "mChannelMask",
+ "I");
+ gAudioGainConfigFields.mValues = env->GetFieldID(audioGainConfigClass, "mValues", "[I");
+ gAudioGainConfigFields.mRampDurationMs = env->GetFieldID(audioGainConfigClass,
+ "mRampDurationMs", "I");
+
+ jclass audioPatchClass = env->FindClass("android/media/AudioPatch");
+ gAudioPatchClass = (jclass) env->NewGlobalRef(audioPatchClass);
+ gAudioPatchCstor = env->GetMethodID(audioPatchClass, "<init>",
+"(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
+ gAudioPatchFields.mHandle = env->GetFieldID(audioPatchClass, "mHandle",
+ "Landroid/media/AudioHandle;");
+
AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
return AndroidRuntime::registerNativeMethods(env,