audio: add JNI AudioAttribute helper class
-Factorize code between AudioRecord & AudioTrack -Prevent memory leak Test: Audio capture and playback smoke tests Change-Id: I06a06cd607754fbbc3e74dd38a66994873c8d9d1 Signed-off-by: François Gaffie <francois.gaffie@renault.com>
This commit is contained in:
committed by
Eric Laurent
parent
e8d1eaa1dc
commit
b4691282f2
@@ -166,6 +166,7 @@ cc_library_shared {
|
||||
"android_media_AudioRecord.cpp",
|
||||
"android_media_AudioSystem.cpp",
|
||||
"android_media_AudioTrack.cpp",
|
||||
"android_media_AudioAttributes.cpp",
|
||||
"android_media_DeviceCallback.cpp",
|
||||
"android_media_JetPlayer.cpp",
|
||||
"android_media_MediaMetricsJNI.cpp",
|
||||
|
||||
@@ -107,6 +107,7 @@ extern int register_android_media_AudioEffectDescriptor(JNIEnv *env);
|
||||
extern int register_android_media_AudioRecord(JNIEnv *env);
|
||||
extern int register_android_media_AudioSystem(JNIEnv *env);
|
||||
extern int register_android_media_AudioTrack(JNIEnv *env);
|
||||
extern int register_android_media_AudioAttributes(JNIEnv *env);
|
||||
extern int register_android_media_MicrophoneInfo(JNIEnv *env);
|
||||
extern int register_android_media_JetPlayer(JNIEnv *env);
|
||||
extern int register_android_media_ToneGenerator(JNIEnv *env);
|
||||
@@ -1470,6 +1471,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_media_AudioSystem),
|
||||
REG_JNI(register_android_media_AudioRecord),
|
||||
REG_JNI(register_android_media_AudioTrack),
|
||||
REG_JNI(register_android_media_AudioAttributes),
|
||||
REG_JNI(register_android_media_JetPlayer),
|
||||
REG_JNI(register_android_media_MicrophoneInfo),
|
||||
REG_JNI(register_android_media_RemoteDisplay),
|
||||
|
||||
205
core/jni/android_media_AudioAttributes.cpp
Normal file
205
core/jni/android_media_AudioAttributes.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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 "AudioAttributes-JNI"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <jni.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <vector>
|
||||
|
||||
#include <nativehelper/ScopedLocalRef.h>
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
#include "android_media_AudioAttributes.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace android;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static const char* const kClassPathName = "android/media/AudioAttributes";
|
||||
|
||||
static jclass gAudioAttributesClass;
|
||||
static struct {
|
||||
jfieldID mUsage; // AudioAttributes.mUsage
|
||||
jfieldID mSource; // AudioAttributes.mSource
|
||||
jfieldID mContentType; // AudioAttributes.mContentType
|
||||
jfieldID mFlags; // AudioAttributes.mFlags
|
||||
jfieldID mFormattedTags; // AudioAttributes.mFormattedTags
|
||||
} gAudioAttributesFields;
|
||||
|
||||
static jclass gAudioAttributesBuilderClass;
|
||||
static jmethodID gAudioAttributesBuilderCstor;
|
||||
static struct {
|
||||
jmethodID build;
|
||||
jmethodID setUsage;
|
||||
jmethodID setInternalCapturePreset;
|
||||
jmethodID setContentType;
|
||||
jmethodID setFlags;
|
||||
jmethodID addTag;
|
||||
} gAudioAttributesBuilderMethods;
|
||||
|
||||
|
||||
static jint nativeAudioAttributesFromJavaAudioAttributes(
|
||||
JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *aa)
|
||||
{
|
||||
if (env == nullptr) {
|
||||
return AUDIO_JAVA_DEAD_OBJECT;
|
||||
}
|
||||
if (jAudioAttributes == nullptr) {
|
||||
ALOGE("Invalid AudioAttributes java object");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
const jstring jtags =
|
||||
(jstring) env->GetObjectField(jAudioAttributes, gAudioAttributesFields.mFormattedTags);
|
||||
if (jtags == nullptr) {
|
||||
return AUDIO_JAVA_NO_INIT;
|
||||
}
|
||||
const char* tags = env->GetStringUTFChars(jtags, NULL);
|
||||
// copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
|
||||
strncpy(aa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
|
||||
env->ReleaseStringUTFChars(jtags, tags);
|
||||
|
||||
// Record ?
|
||||
aa->source = (audio_source_t) env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mSource);
|
||||
// Track ?
|
||||
aa->usage = (audio_usage_t) env->GetIntField(jAudioAttributes, gAudioAttributesFields.mUsage);
|
||||
|
||||
aa->content_type =
|
||||
(audio_content_type_t) env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mContentType);
|
||||
|
||||
aa->flags = (audio_flags_mask_t)env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mFlags);
|
||||
|
||||
ALOGV("AudioAttributes for usage=%d content=%d source=%d tags=%s flags=%08x tags=%s",
|
||||
aa->usage, aa->content_type, aa->source, aa->tags, aa->flags, aa->tags);
|
||||
return (jint)AUDIO_JAVA_SUCCESS;
|
||||
}
|
||||
|
||||
static jint nativeAudioAttributesToJavaAudioAttributes(
|
||||
JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
|
||||
{
|
||||
ScopedLocalRef<jobject> jAttributeBuilder(env, env->NewObject(gAudioAttributesBuilderClass,
|
||||
gAudioAttributesBuilderCstor));
|
||||
if (jAttributeBuilder.get() == nullptr) {
|
||||
return (jint)AUDIO_JAVA_ERROR;
|
||||
}
|
||||
env->CallObjectMethod(jAttributeBuilder.get(),
|
||||
gAudioAttributesBuilderMethods.setUsage,
|
||||
attributes.usage);
|
||||
env->CallObjectMethod(jAttributeBuilder.get(),
|
||||
gAudioAttributesBuilderMethods.setInternalCapturePreset,
|
||||
attributes.source);
|
||||
env->CallObjectMethod(jAttributeBuilder.get(),
|
||||
gAudioAttributesBuilderMethods.setContentType,
|
||||
attributes.content_type);
|
||||
env->CallObjectMethod(jAttributeBuilder.get(),
|
||||
gAudioAttributesBuilderMethods.setFlags,
|
||||
attributes.flags);
|
||||
env->CallObjectMethod(jAttributeBuilder.get(),
|
||||
gAudioAttributesBuilderMethods.addTag,
|
||||
env->NewStringUTF(attributes.tags));
|
||||
|
||||
*jAudioAttributes = env->CallObjectMethod(jAttributeBuilder.get(),
|
||||
gAudioAttributesBuilderMethods.build);
|
||||
return (jint)AUDIO_JAVA_SUCCESS;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
JNIAudioAttributeHelper::UniqueAaPtr JNIAudioAttributeHelper::makeUnique()
|
||||
{
|
||||
audio_attributes_t *aa = new (calloc(1, sizeof(audio_attributes_t)))
|
||||
audio_attributes_t{AUDIO_ATTRIBUTES_INITIALIZER};
|
||||
return UniqueAaPtr{aa, free};
|
||||
}
|
||||
|
||||
jint JNIAudioAttributeHelper::nativeFromJava(JNIEnv* env, jobject jAudioAttributes,
|
||||
audio_attributes_t *paa)
|
||||
{
|
||||
return nativeAudioAttributesFromJavaAudioAttributes(env, jAudioAttributes, paa);
|
||||
}
|
||||
|
||||
jint JNIAudioAttributeHelper::nativeToJava(
|
||||
JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
|
||||
{
|
||||
return nativeAudioAttributesToJavaAudioAttributes(env, jAudioAttributes, attributes);
|
||||
}
|
||||
|
||||
jint JNIAudioAttributeHelper::getJavaArray(
|
||||
JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes)
|
||||
{
|
||||
*jAudioAttributeArray = env->NewObjectArray(numAudioAttributes, gAudioAttributesClass, NULL);
|
||||
return jAudioAttributeArray == NULL? (jint)AUDIO_JAVA_ERROR : (jint)AUDIO_JAVA_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* JNI registration.
|
||||
*/
|
||||
static const JNINativeMethod gMethods[] = {
|
||||
// n/a
|
||||
};
|
||||
|
||||
int register_android_media_AudioAttributes(JNIEnv *env)
|
||||
{
|
||||
jclass audioAttributesClass = FindClassOrDie(env, kClassPathName);
|
||||
gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
|
||||
gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
|
||||
gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
|
||||
gAudioAttributesFields.mContentType =
|
||||
GetFieldIDOrDie(env, audioAttributesClass, "mContentType", "I");
|
||||
gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
|
||||
gAudioAttributesFields.mFormattedTags =
|
||||
GetFieldIDOrDie(env, audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
|
||||
|
||||
jclass audioAttributesBuilderClass = FindClassOrDie(
|
||||
env, "android/media/AudioAttributes$Builder");
|
||||
gAudioAttributesBuilderClass = MakeGlobalRefOrDie(env, audioAttributesBuilderClass);
|
||||
gAudioAttributesBuilderCstor = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "<init>", "()V");
|
||||
gAudioAttributesBuilderMethods.build = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "build", "()Landroid/media/AudioAttributes;");
|
||||
gAudioAttributesBuilderMethods.setUsage = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "setUsage",
|
||||
"(I)Landroid/media/AudioAttributes$Builder;");
|
||||
gAudioAttributesBuilderMethods.setInternalCapturePreset = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "setInternalCapturePreset",
|
||||
"(I)Landroid/media/AudioAttributes$Builder;");
|
||||
gAudioAttributesBuilderMethods.setContentType = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "setContentType",
|
||||
"(I)Landroid/media/AudioAttributes$Builder;");
|
||||
gAudioAttributesBuilderMethods.setFlags = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "setFlags",
|
||||
"(I)Landroid/media/AudioAttributes$Builder;");
|
||||
gAudioAttributesBuilderMethods.addTag = GetMethodIDOrDie(
|
||||
env, audioAttributesBuilderClass, "addTag",
|
||||
"(Ljava/lang/String;)Landroid/media/AudioAttributes$Builder;");
|
||||
|
||||
env->DeleteLocalRef(audioAttributesClass);
|
||||
|
||||
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
|
||||
}
|
||||
70
core/jni/android_media_AudioAttributes.h
Normal file
70
core/jni/android_media_AudioAttributes.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include <system/audio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class JNIAudioAttributeHelper
|
||||
{
|
||||
public:
|
||||
using UniqueAaPtr = std::unique_ptr<audio_attributes_t, decltype(free)*>;
|
||||
|
||||
/**
|
||||
* @brief makeUnique helper to prevent leak
|
||||
* @return a unique ptr of 0-initialized native audio attributes structure
|
||||
*/
|
||||
static UniqueAaPtr makeUnique();
|
||||
|
||||
/**
|
||||
* @brief nativeFromJava Gets the underlying AudioAttributes from an AudioAttributes Java
|
||||
* object.
|
||||
* @param env
|
||||
* @param jAudioAttributes JAVA AudioAttribute object
|
||||
* @param paa native AudioAttribute pointer
|
||||
* @return AUDIO_JAVA_SUCCESS on success, error code otherwise
|
||||
*/
|
||||
static jint nativeFromJava(
|
||||
JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *attributes);
|
||||
|
||||
/**
|
||||
* @brief nativeToJava AudioAttributes Java object from a native AudioAttributes.
|
||||
* @param env
|
||||
* @param jAudioAttributes JAVA AudioAttribute object
|
||||
* @param attributes native AudioAttribute
|
||||
* @return AUDIO_JAVA_SUCCESS on success, error code otherwise
|
||||
*/
|
||||
static jint nativeToJava(
|
||||
JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes);
|
||||
|
||||
/**
|
||||
* @brief getJavaArray: creates an array of JAVA AudioAttributes objects
|
||||
* @param env
|
||||
* @param jAudioAttributeArray
|
||||
* @param numAudioAttributes
|
||||
* @return Array of AudioAttributes objects
|
||||
*/
|
||||
static jint getJavaArray(
|
||||
JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes);
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "android_media_DeviceCallback.h"
|
||||
#include "android_media_MediaMetricsJNI.h"
|
||||
#include "android_media_MicrophoneInfo.h"
|
||||
#include "android_media_AudioAttributes.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -42,7 +43,6 @@ using namespace android;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static const char* const kClassPathName = "android/media/AudioRecord";
|
||||
static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
|
||||
|
||||
static jclass gArrayListClass;
|
||||
static struct {
|
||||
@@ -56,12 +56,6 @@ struct audio_record_fields_t {
|
||||
jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
|
||||
jfieldID nativeDeviceCallback; // provides access to the JNIDeviceCallback instance
|
||||
};
|
||||
struct audio_attributes_fields_t {
|
||||
jfieldID fieldRecSource; // AudioAttributes.mSource
|
||||
jfieldID fieldFlags; // AudioAttributes.mFlags
|
||||
jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
|
||||
};
|
||||
static audio_attributes_fields_t javaAudioAttrFields;
|
||||
static audio_record_fields_t javaAudioRecordFields;
|
||||
static struct {
|
||||
jfieldID fieldFramePosition; // AudioTimestamp.framePosition
|
||||
@@ -213,7 +207,6 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
|
||||
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
|
||||
nSession = NULL;
|
||||
|
||||
audio_attributes_t *paa = NULL;
|
||||
sp<AudioRecord> lpRecorder = 0;
|
||||
audiorecord_callback_cookie *lpCallbackData = NULL;
|
||||
|
||||
@@ -275,15 +268,11 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
|
||||
lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
|
||||
|
||||
// read the AudioAttributes values
|
||||
paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
|
||||
const jstring jtags =
|
||||
(jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
|
||||
const char* tags = env->GetStringUTFChars(jtags, NULL);
|
||||
// copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
|
||||
strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
|
||||
env->ReleaseStringUTFChars(jtags, tags);
|
||||
paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
|
||||
paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
|
||||
auto paa = JNIAudioAttributeHelper::makeUnique();
|
||||
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
|
||||
if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
|
||||
|
||||
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
|
||||
@@ -311,7 +300,7 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
|
||||
AudioRecord::TRANSFER_DEFAULT,
|
||||
flags,
|
||||
-1, -1, // default uid, pid
|
||||
paa);
|
||||
paa.get());
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
|
||||
@@ -368,19 +357,10 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
|
||||
// of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
|
||||
|
||||
if (paa != NULL) {
|
||||
// audio attributes were copied in AudioRecord creation
|
||||
free(paa);
|
||||
paa = NULL;
|
||||
}
|
||||
|
||||
return (jint) AUDIO_JAVA_SUCCESS;
|
||||
|
||||
// failure:
|
||||
native_init_failure:
|
||||
if (paa != NULL) {
|
||||
free(paa);
|
||||
}
|
||||
env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
|
||||
env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
|
||||
delete lpCallbackData;
|
||||
@@ -972,13 +952,6 @@ int register_android_media_AudioRecord(JNIEnv *env)
|
||||
javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
|
||||
|
||||
// Get the AudioAttributes class and fields
|
||||
jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
|
||||
javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
|
||||
javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
|
||||
javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
|
||||
audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
|
||||
|
||||
// Get the RecordTimestamp class and fields
|
||||
jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
|
||||
javaAudioTimestampFields.fieldFramePosition =
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "android_media_AudioFormat.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
#include "android_media_MicrophoneInfo.h"
|
||||
#include "android_media_AudioAttributes.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -153,15 +154,6 @@ static struct {
|
||||
jfieldID mRule;
|
||||
} gAudioMixMatchCriterionFields;
|
||||
|
||||
static jclass gAudioAttributesClass;
|
||||
static struct {
|
||||
jfieldID mUsage;
|
||||
jfieldID mSource;
|
||||
jfieldID mContentType;
|
||||
jfieldID mFlags;
|
||||
jfieldID mFormattedTags;
|
||||
} gAudioAttributesFields;
|
||||
|
||||
static const char* const kEventHandlerClassPathName =
|
||||
"android/media/AudioPortEventHandler";
|
||||
static struct {
|
||||
@@ -705,27 +697,6 @@ static void convertAudioGainConfigToNative(JNIEnv *env,
|
||||
env->DeleteLocalRef(jValues);
|
||||
}
|
||||
|
||||
static jint convertAudioAttributesToNative(JNIEnv *env,
|
||||
audio_attributes_t *nAudioAttributes,
|
||||
const jobject jAudioAttributes)
|
||||
{
|
||||
nAudioAttributes->usage = (audio_usage_t)env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mUsage);
|
||||
nAudioAttributes->source = (audio_source_t)env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mSource);
|
||||
nAudioAttributes->content_type = (audio_content_type_t)env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mContentType);
|
||||
nAudioAttributes->flags = env->GetIntField(jAudioAttributes,
|
||||
gAudioAttributesFields.mFlags);
|
||||
const jstring jtags = (jstring)env->GetObjectField(jAudioAttributes,
|
||||
gAudioAttributesFields.mFormattedTags);
|
||||
const char *tags = env->GetStringUTFChars(jtags, NULL);
|
||||
strncpy(nAudioAttributes->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
|
||||
env->ReleaseStringUTFChars(jtags, tags);
|
||||
return (jint)AUDIO_JAVA_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static jint convertAudioPortConfigToNative(JNIEnv *env,
|
||||
struct audio_port_config *nAudioPortConfig,
|
||||
const jobject jAudioPortConfig,
|
||||
@@ -1705,22 +1676,19 @@ android_media_AudioSystem_startAudioSource(JNIEnv *env, jobject clazz,
|
||||
if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
|
||||
return AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
|
||||
return AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
struct audio_port_config nAudioPortConfig = {};
|
||||
jint jStatus = convertAudioPortConfigToNativeWithDevicePort(env,
|
||||
&nAudioPortConfig, jAudioPortConfig, false);
|
||||
if (jStatus != AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
audio_attributes_t nAudioAttributes = {};
|
||||
jStatus = convertAudioAttributesToNative(env, &nAudioAttributes, jAudioAttributes);
|
||||
if (jStatus != AUDIO_JAVA_SUCCESS) {
|
||||
auto paa = JNIAudioAttributeHelper::makeUnique();
|
||||
jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
|
||||
if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
audio_port_handle_t handle;
|
||||
status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, &nAudioAttributes, &handle);
|
||||
status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, paa.get(), &handle);
|
||||
ALOGV("AudioSystem::startAudioSource() returned %d handle %d", status, handle);
|
||||
return handle > 0 ? handle : nativeToJavaStatus(status);
|
||||
}
|
||||
@@ -1833,12 +1801,16 @@ static jint convertAudioMixToNative(JNIEnv *env,
|
||||
case RULE_MATCH_ATTRIBUTE_USAGE:
|
||||
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
|
||||
jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
|
||||
|
||||
auto paa = JNIAudioAttributeHelper::makeUnique();
|
||||
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAttributes, paa.get());
|
||||
if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
|
||||
nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
|
||||
gAudioAttributesFields.mUsage);
|
||||
nCriterion.mValue.mUsage = paa->usage;
|
||||
} else {
|
||||
nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
|
||||
gAudioAttributesFields.mSource);
|
||||
nCriterion.mValue.mSource = paa->source;
|
||||
}
|
||||
env->DeleteLocalRef(jAttributes);
|
||||
}
|
||||
@@ -2395,17 +2367,6 @@ int register_android_media_AudioSystem(JNIEnv *env)
|
||||
"I");
|
||||
gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
|
||||
"I");
|
||||
|
||||
jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
|
||||
gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
|
||||
gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
|
||||
gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
|
||||
gAudioAttributesFields.mContentType = GetFieldIDOrDie(env,
|
||||
audioAttributesClass, "mContentType", "I");
|
||||
gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
|
||||
gAudioAttributesFields.mFormattedTags = GetFieldIDOrDie(env,
|
||||
audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
|
||||
|
||||
// AudioTrackRoutingProxy methods
|
||||
gClsAudioTrackRoutingProxy =
|
||||
android::FindClassOrDie(env, "android/media/AudioTrackRoutingProxy");
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "android_media_PlaybackParams.h"
|
||||
#include "android_media_DeviceCallback.h"
|
||||
#include "android_media_VolumeShaper.h"
|
||||
#include "android_media_AudioAttributes.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
@@ -48,7 +49,6 @@ using ::android::media::VolumeShaper;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static const char* const kClassPathName = "android/media/AudioTrack";
|
||||
static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
|
||||
|
||||
struct audio_track_fields_t {
|
||||
// these fields provide access from C++ to the...
|
||||
@@ -57,14 +57,7 @@ struct audio_track_fields_t {
|
||||
jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
|
||||
jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
|
||||
};
|
||||
struct audio_attributes_fields_t {
|
||||
jfieldID fieldUsage; // AudioAttributes.mUsage
|
||||
jfieldID fieldContentType; // AudioAttributes.mContentType
|
||||
jfieldID fieldFlags; // AudioAttributes.mFlags
|
||||
jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
|
||||
};
|
||||
static audio_track_fields_t javaAudioTrackFields;
|
||||
static audio_attributes_fields_t javaAudioAttrFields;
|
||||
static PlaybackParams::fields_t gPlaybackParamsFields;
|
||||
static VolumeShaperHelper::fields_t gVolumeShaperFields;
|
||||
|
||||
@@ -249,8 +242,6 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
|
||||
|
||||
AudioTrackJniStorage* lpJniStorage = NULL;
|
||||
|
||||
audio_attributes_t *paa = NULL;
|
||||
|
||||
jclass clazz = env->GetObjectClass(thiz);
|
||||
if (clazz == NULL) {
|
||||
ALOGE("Can't find %s when setting up callback.", kClassPathName);
|
||||
@@ -304,18 +295,11 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
|
||||
lpTrack = new AudioTrack();
|
||||
|
||||
// read the AudioAttributes values
|
||||
paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
|
||||
const jstring jtags =
|
||||
(jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
|
||||
const char* tags = env->GetStringUTFChars(jtags, NULL);
|
||||
// copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
|
||||
strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
|
||||
env->ReleaseStringUTFChars(jtags, tags);
|
||||
paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
|
||||
paa->content_type =
|
||||
(audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
|
||||
paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
|
||||
|
||||
auto paa = JNIAudioAttributeHelper::makeUnique();
|
||||
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
|
||||
if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
|
||||
paa->usage, paa->content_type, paa->flags, paa->tags);
|
||||
|
||||
@@ -357,7 +341,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
|
||||
offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
|
||||
offload ? &offloadInfo : NULL,
|
||||
-1, -1, // default uid, pid values
|
||||
paa);
|
||||
paa.get());
|
||||
|
||||
break;
|
||||
|
||||
@@ -384,7 +368,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
|
||||
AudioTrack::TRANSFER_SHARED,
|
||||
NULL, // default offloadInfo
|
||||
-1, -1, // default uid, pid values
|
||||
paa);
|
||||
paa.get());
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -452,20 +436,11 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
|
||||
// since we had audio attributes, the stream type was derived from them during the
|
||||
// creation of the native AudioTrack: push the same value to the Java object
|
||||
env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
|
||||
if (paa != NULL) {
|
||||
// audio attributes were copied in AudioTrack creation
|
||||
free(paa);
|
||||
paa = NULL;
|
||||
}
|
||||
|
||||
|
||||
return (jint) AUDIO_JAVA_SUCCESS;
|
||||
|
||||
// failures:
|
||||
native_init_failure:
|
||||
if (paa != NULL) {
|
||||
free(paa);
|
||||
}
|
||||
if (nSession != NULL) {
|
||||
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
|
||||
}
|
||||
@@ -1470,17 +1445,6 @@ int register_android_media_AudioTrack(JNIEnv *env)
|
||||
|
||||
env->DeleteLocalRef(audioTrackClass);
|
||||
|
||||
// Get the AudioAttributes class and fields
|
||||
jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
|
||||
javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
|
||||
javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
|
||||
audioAttrClass, "mContentType", "I");
|
||||
javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
|
||||
javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
|
||||
audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
|
||||
|
||||
env->DeleteLocalRef(audioAttrClass);
|
||||
|
||||
// initialize PlaybackParams field info
|
||||
gPlaybackParamsFields.init(env);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user