Merge "Update AudioRecord JNI callback and cleanup" into tm-dev
This commit is contained in:
@@ -33,12 +33,13 @@
|
||||
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
#include "android_media_AudioAttributes.h"
|
||||
#include "android_media_AudioFormat.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
#include "android_media_DeviceCallback.h"
|
||||
#include "android_media_JNIUtils.h"
|
||||
#include "android_media_MediaMetricsJNI.h"
|
||||
#include "android_media_MicrophoneInfo.h"
|
||||
#include "android_media_AudioAttributes.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -57,8 +58,7 @@ struct audio_record_fields_t {
|
||||
// these fields provide access from C++ to the...
|
||||
jmethodID postNativeEventInJava; //... event post callback method
|
||||
jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
|
||||
jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
|
||||
jfieldID nativeDeviceCallback; // provides access to the JNIDeviceCallback instance
|
||||
jfieldID jniData; // provides access to AudioRecord JNI Handle
|
||||
};
|
||||
static audio_record_fields_t javaAudioRecordFields;
|
||||
static struct {
|
||||
@@ -66,15 +66,68 @@ static struct {
|
||||
jfieldID fieldNanoTime; // AudioTimestamp.nanoTime
|
||||
} javaAudioTimestampFields;
|
||||
|
||||
struct audiorecord_callback_cookie {
|
||||
jclass audioRecord_class;
|
||||
jobject audioRecord_ref;
|
||||
bool busy;
|
||||
Condition cond;
|
||||
};
|
||||
|
||||
static Mutex sLock;
|
||||
static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
|
||||
class AudioRecordJNIStorage : public AudioRecord::IAudioRecordCallback {
|
||||
private:
|
||||
// Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*.
|
||||
enum class EventType {
|
||||
EVENT_MORE_DATA = 0, // Request to read available data from buffer.
|
||||
// If this event is delivered but the callback handler
|
||||
// does not want to read the available data, the handler must
|
||||
// explicitly ignore the event by setting frameCount to zero.
|
||||
EVENT_OVERRUN = 1, // Buffer overrun occurred.
|
||||
EVENT_MARKER = 2, // Record head is at the specified marker position
|
||||
// (See setMarkerPosition()).
|
||||
EVENT_NEW_POS = 3, // Record head is at a new position
|
||||
// (See setPositionUpdatePeriod()).
|
||||
EVENT_NEW_IAUDIORECORD = 4, // IAudioRecord was re-created, either due to re-routing and
|
||||
// voluntary invalidation by mediaserver, or mediaserver crash.
|
||||
};
|
||||
|
||||
public:
|
||||
AudioRecordJNIStorage(jclass audioRecordClass, jobject audioRecordWeakRef)
|
||||
: mAudioRecordClass(audioRecordClass), mAudioRecordWeakRef(audioRecordWeakRef) {}
|
||||
AudioRecordJNIStorage(const AudioRecordJNIStorage &) = delete;
|
||||
AudioRecordJNIStorage& operator=(const AudioRecordJNIStorage &) = delete;
|
||||
|
||||
void onMarker(uint32_t) override {
|
||||
postEvent(EventType::EVENT_MARKER);
|
||||
}
|
||||
|
||||
void onNewPos(uint32_t) override {
|
||||
postEvent(EventType::EVENT_NEW_POS);
|
||||
}
|
||||
|
||||
void setDeviceCallback(const sp<JNIDeviceCallback>& callback) {
|
||||
mDeviceCallback = callback;
|
||||
}
|
||||
|
||||
sp<JNIDeviceCallback> getDeviceCallback() const { return mDeviceCallback; }
|
||||
|
||||
jobject getAudioTrackWeakRef() const & { return mAudioRecordWeakRef.get(); }
|
||||
|
||||
// If we attempt to get a jobject from a rvalue, it will soon go out of
|
||||
// scope, and the reference count can drop to zero, which is unsafe.
|
||||
jobject getAudioTrackWeakRef() const && = delete;
|
||||
|
||||
private:
|
||||
void postEvent(EventType event, int arg = 0) const {
|
||||
JNIEnv *env = getJNIEnvOrDie();
|
||||
env->CallStaticVoidMethod(
|
||||
static_cast<jclass>(mAudioRecordClass.get()),
|
||||
javaAudioRecordFields.postNativeEventInJava,
|
||||
mAudioRecordWeakRef.get(), static_cast<int>(event), arg, 0, nullptr);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
// Mutation of this object is protected using Java concurrency constructs
|
||||
sp<JNIDeviceCallback> mDeviceCallback;
|
||||
const GlobalRef mAudioRecordClass;
|
||||
const GlobalRef mAudioRecordWeakRef;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -84,104 +137,10 @@ static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
|
||||
#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE (-19)
|
||||
#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED (-20)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static void recorderCallback(int event, void* user, void *info) {
|
||||
|
||||
audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
|
||||
return;
|
||||
}
|
||||
callbackInfo->busy = true;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case AudioRecord::EVENT_MARKER: {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
if (user != NULL && env != NULL) {
|
||||
env->CallStaticVoidMethod(
|
||||
callbackInfo->audioRecord_class,
|
||||
javaAudioRecordFields.postNativeEventInJava,
|
||||
callbackInfo->audioRecord_ref, event, 0,0, NULL);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case AudioRecord::EVENT_NEW_POS: {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
if (user != NULL && env != NULL) {
|
||||
env->CallStaticVoidMethod(
|
||||
callbackInfo->audioRecord_class,
|
||||
javaAudioRecordFields.postNativeEventInJava,
|
||||
callbackInfo->audioRecord_ref, event, 0,0, NULL);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
callbackInfo->busy = false;
|
||||
callbackInfo->cond.broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
JNIDeviceCallback* const cb =
|
||||
(JNIDeviceCallback*)env->GetLongField(thiz,
|
||||
javaAudioRecordFields.nativeDeviceCallback);
|
||||
return sp<JNIDeviceCallback>(cb);
|
||||
}
|
||||
|
||||
static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
|
||||
jobject thiz,
|
||||
const sp<JNIDeviceCallback>& cb)
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
sp<JNIDeviceCallback> old =
|
||||
(JNIDeviceCallback*)env->GetLongField(thiz,
|
||||
javaAudioRecordFields.nativeDeviceCallback);
|
||||
if (cb.get()) {
|
||||
cb->incStrong((void*)setJniDeviceCallback);
|
||||
}
|
||||
if (old != 0) {
|
||||
old->decStrong((void*)setJniDeviceCallback);
|
||||
}
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
|
||||
return old;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
AudioRecord* const ar =
|
||||
(AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
|
||||
return sp<AudioRecord>(ar);
|
||||
}
|
||||
|
||||
static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
sp<AudioRecord> old =
|
||||
(AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
|
||||
if (ar.get()) {
|
||||
ar->incStrong((void*)setAudioRecord);
|
||||
}
|
||||
if (old != 0) {
|
||||
old->decStrong((void*)setAudioRecord);
|
||||
}
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
|
||||
return old;
|
||||
return getFieldSp<AudioRecord>(env, thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -211,9 +170,8 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w
|
||||
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
|
||||
nSession = NULL;
|
||||
|
||||
sp<AudioRecord> lpRecorder = 0;
|
||||
audiorecord_callback_cookie *lpCallbackData = NULL;
|
||||
|
||||
sp<AudioRecord> lpRecorder;
|
||||
sp<AudioRecordJNIStorage> callbackData;
|
||||
jclass clazz = env->GetObjectClass(thiz);
|
||||
if (clazz == NULL) {
|
||||
ALOGE("Can't find %s when setting up callback.", kClassPathName);
|
||||
@@ -287,18 +245,14 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w
|
||||
}
|
||||
// create the callback information:
|
||||
// this data will be passed with every AudioRecord callback
|
||||
lpCallbackData = new audiorecord_callback_cookie;
|
||||
lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
|
||||
// we use a weak reference so the AudioRecord object can be garbage collected.
|
||||
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
|
||||
lpCallbackData->busy = false;
|
||||
callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
|
||||
|
||||
const status_t status =
|
||||
lpRecorder->set(paa->source, sampleRateInHertz,
|
||||
format, // word length, PCM
|
||||
localChanMask, frameCount,
|
||||
recorderCallback, // callback_t
|
||||
lpCallbackData, // void* user
|
||||
callbackData, // callback
|
||||
0, // notificationFrames,
|
||||
true, // threadCanCallJava
|
||||
sessionId, AudioRecord::TRANSFER_DEFAULT, flags, -1,
|
||||
@@ -330,11 +284,8 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w
|
||||
|
||||
// create the callback information:
|
||||
// this data will be passed with every AudioRecord callback
|
||||
lpCallbackData = new audiorecord_callback_cookie;
|
||||
lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
|
||||
// we use a weak reference so the AudioRecord object can be garbage collected.
|
||||
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
|
||||
lpCallbackData->busy = false;
|
||||
// This next line makes little sense
|
||||
// callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
|
||||
}
|
||||
|
||||
nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
|
||||
@@ -352,26 +303,20 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w
|
||||
env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
|
||||
}
|
||||
|
||||
{ // scope for the lock
|
||||
Mutex::Autolock l(sLock);
|
||||
sAudioRecordCallBackCookies.add(lpCallbackData);
|
||||
}
|
||||
// save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
|
||||
// of the Java object
|
||||
setAudioRecord(env, thiz, lpRecorder);
|
||||
setFieldSp(env, thiz, lpRecorder, javaAudioRecordFields.nativeRecorderInJavaObj);
|
||||
|
||||
// save our newly created callback information in the "nativeCallbackCookie" field
|
||||
// of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
|
||||
// save our newly created callback information in the "jniData" field
|
||||
// of the Java object (in mNativeJNIDataHandle) so we can free the memory in finalize()
|
||||
setFieldSp(env, thiz, callbackData, javaAudioRecordFields.jniData);
|
||||
|
||||
return (jint) AUDIO_JAVA_SUCCESS;
|
||||
|
||||
// failure:
|
||||
native_init_failure:
|
||||
env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
|
||||
env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
|
||||
delete lpCallbackData;
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
|
||||
setFieldSp(env, thiz, sp<AudioRecord>{}, javaAudioRecordFields.nativeRecorderInJavaObj);
|
||||
setFieldSp(env, thiz, sp<AudioRecordJNIStorage>{}, javaAudioRecordFields.jniData);
|
||||
|
||||
// lpRecorder goes out of scope, so reference count drops to zero
|
||||
return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
|
||||
@@ -411,36 +356,9 @@ android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
|
||||
|
||||
#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
|
||||
static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) {
|
||||
sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
|
||||
if (lpRecorder == NULL) {
|
||||
return;
|
||||
}
|
||||
ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
|
||||
lpRecorder->stop();
|
||||
|
||||
audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
|
||||
thiz, javaAudioRecordFields.nativeCallbackCookie);
|
||||
|
||||
// reset the native resources in the Java object so any attempt to access
|
||||
// them after a call to release fails.
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
|
||||
|
||||
// delete the callback information
|
||||
if (lpCookie) {
|
||||
Mutex::Autolock l(sLock);
|
||||
ALOGV("deleting lpCookie: %p", lpCookie);
|
||||
while (lpCookie->busy) {
|
||||
if (lpCookie->cond.waitRelative(sLock,
|
||||
milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
|
||||
NO_ERROR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sAudioRecordCallBackCookies.remove(lpCookie);
|
||||
env->DeleteGlobalRef(lpCookie->audioRecord_class);
|
||||
env->DeleteGlobalRef(lpCookie->audioRecord_ref);
|
||||
delete lpCookie;
|
||||
}
|
||||
setFieldSp(env, thiz, sp<AudioRecord>{}, javaAudioRecordFields.nativeRecorderInJavaObj);
|
||||
setFieldSp(env, thiz, sp<AudioRecordJNIStorage>{}, javaAudioRecordFields.jniData);
|
||||
}
|
||||
|
||||
|
||||
@@ -685,43 +603,40 @@ static jint android_media_AudioRecord_getRoutedDeviceId(
|
||||
return (jint)lpRecorder->getRoutedDeviceId();
|
||||
}
|
||||
|
||||
// Enable and Disable Callback methods are synchronized on the Java side
|
||||
static void android_media_AudioRecord_enableDeviceCallback(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == 0) {
|
||||
if (lpRecorder == nullptr) {
|
||||
return;
|
||||
}
|
||||
sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
|
||||
if (cb != 0) {
|
||||
return;
|
||||
}
|
||||
audiorecord_callback_cookie *cookie =
|
||||
(audiorecord_callback_cookie *)env->GetLongField(thiz,
|
||||
javaAudioRecordFields.nativeCallbackCookie);
|
||||
if (cookie == NULL) {
|
||||
const auto pJniStorage =
|
||||
getFieldSp<AudioRecordJNIStorage>(env, thiz, javaAudioRecordFields.jniData);
|
||||
if (pJniStorage == nullptr || pJniStorage->getDeviceCallback() != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
|
||||
javaAudioRecordFields.postNativeEventInJava);
|
||||
status_t status = lpRecorder->addAudioDeviceCallback(cb);
|
||||
if (status == NO_ERROR) {
|
||||
setJniDeviceCallback(env, thiz, cb);
|
||||
}
|
||||
pJniStorage->setDeviceCallback(
|
||||
sp<JNIDeviceCallback>::make(env, thiz, pJniStorage->getAudioTrackWeakRef(),
|
||||
javaAudioRecordFields.postNativeEventInJava));
|
||||
lpRecorder->addAudioDeviceCallback(pJniStorage->getDeviceCallback());
|
||||
}
|
||||
|
||||
static void android_media_AudioRecord_disableDeviceCallback(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == 0) {
|
||||
if (lpRecorder == nullptr) {
|
||||
return;
|
||||
}
|
||||
sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
|
||||
if (cb != 0) {
|
||||
lpRecorder->removeAudioDeviceCallback(cb);
|
||||
const auto pJniStorage =
|
||||
getFieldSp<AudioRecordJNIStorage>(env, thiz, javaAudioRecordFields.jniData);
|
||||
|
||||
if (pJniStorage == nullptr || pJniStorage->getDeviceCallback() == nullptr) {
|
||||
return;
|
||||
}
|
||||
lpRecorder->removeAudioDeviceCallback(pJniStorage->getDeviceCallback());
|
||||
pJniStorage->setDeviceCallback(nullptr);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -962,17 +877,15 @@ static const JNINativeMethod gMethods[] = {
|
||||
|
||||
// field names found in android/media/AudioRecord.java
|
||||
#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
|
||||
#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj"
|
||||
#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie"
|
||||
#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME "mNativeDeviceCallback"
|
||||
#define JAVA_NATIVEAUDIORECORDERHANDLE_FIELD_NAME "mNativeAudioRecordHandle"
|
||||
#define JAVA_NATIVEJNIDATAHANDLE_FIELD_NAME "mNativeJNIDataHandle"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int register_android_media_AudioRecord(JNIEnv *env)
|
||||
{
|
||||
javaAudioRecordFields.postNativeEventInJava = NULL;
|
||||
javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
|
||||
javaAudioRecordFields.nativeCallbackCookie = NULL;
|
||||
javaAudioRecordFields.nativeDeviceCallback = NULL;
|
||||
javaAudioRecordFields.jniData = NULL;
|
||||
|
||||
|
||||
// Get the AudioRecord class
|
||||
@@ -983,15 +896,12 @@ int register_android_media_AudioRecord(JNIEnv *env)
|
||||
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
|
||||
|
||||
// Get the variables
|
||||
// mNativeRecorderInJavaObj
|
||||
// mNativeAudioRecordHandle
|
||||
javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
|
||||
// mNativeCallbackCookie
|
||||
javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
|
||||
|
||||
javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
|
||||
audioRecordClass, JAVA_NATIVEAUDIORECORDERHANDLE_FIELD_NAME, "J");
|
||||
// mNativeJNIDataHandle
|
||||
javaAudioRecordFields.jniData = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVEJNIDATAHANDLE_FIELD_NAME, "J");
|
||||
|
||||
// Get the RecordTimestamp class and fields
|
||||
jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
|
||||
|
||||
@@ -64,5 +64,39 @@ inline JNIEnv* getJNIEnvOrDie() {
|
||||
return env;
|
||||
}
|
||||
|
||||
class GlobalRef {
|
||||
public:
|
||||
GlobalRef(jobject object) : GlobalRef(object, AndroidRuntime::getJNIEnv()) {}
|
||||
|
||||
GlobalRef(jobject object, JNIEnv* env) {
|
||||
LOG_ALWAYS_FATAL_IF(env == nullptr, "Invalid JNIEnv when attempting to create a GlobalRef");
|
||||
mGlobalRef = env->NewGlobalRef(object);
|
||||
LOG_ALWAYS_FATAL_IF(env->IsSameObject(object, nullptr) == JNI_TRUE,
|
||||
"Creating GlobalRef from null object");
|
||||
}
|
||||
|
||||
GlobalRef(const GlobalRef& other) : GlobalRef(other.mGlobalRef) {}
|
||||
|
||||
GlobalRef(GlobalRef&& other) : mGlobalRef(other.mGlobalRef) { other.mGlobalRef = nullptr; }
|
||||
|
||||
// Logically const
|
||||
GlobalRef& operator=(const GlobalRef& other) = delete;
|
||||
|
||||
GlobalRef& operator=(GlobalRef&& other) = delete;
|
||||
|
||||
~GlobalRef() {
|
||||
if (mGlobalRef == nullptr) return; // No reference to decrement
|
||||
getJNIEnvOrDie()->DeleteGlobalRef(mGlobalRef);
|
||||
}
|
||||
|
||||
// Valid as long as this wrapper is in scope.
|
||||
jobject get() const {
|
||||
return mGlobalRef;
|
||||
}
|
||||
|
||||
private:
|
||||
// Logically const. Not actually const so we can move from GlobalRef
|
||||
jobject mGlobalRef;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -187,22 +187,14 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@UnsupportedAppUsage
|
||||
private long mNativeRecorderInJavaObj;
|
||||
private long mNativeAudioRecordHandle;
|
||||
|
||||
/**
|
||||
* Accessed by native methods: provides access to the callback data.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
private long mNativeCallbackCookie;
|
||||
|
||||
/**
|
||||
* Accessed by native methods: provides access to the JNIDeviceCallback instance.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
private long mNativeDeviceCallback;
|
||||
|
||||
private long mNativeJNIDataHandle;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Member variables
|
||||
@@ -492,9 +484,8 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
* value here as no error checking is or can be done.
|
||||
*/
|
||||
/*package*/ AudioRecord(long nativeRecordInJavaObj) {
|
||||
mNativeRecorderInJavaObj = 0;
|
||||
mNativeCallbackCookie = 0;
|
||||
mNativeDeviceCallback = 0;
|
||||
mNativeAudioRecordHandle = 0;
|
||||
mNativeJNIDataHandle = 0;
|
||||
|
||||
// other initialization...
|
||||
if (nativeRecordInJavaObj != 0) {
|
||||
@@ -2131,7 +2122,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
* @hide
|
||||
*/
|
||||
public int getPortId() {
|
||||
if (mNativeRecorderInJavaObj == 0) {
|
||||
if (mNativeAudioRecordHandle == 0) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user