Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfb20d93 authored by Atneya Nair's avatar Atneya Nair Committed by Automerger Merge Worker
Browse files

Merge "Move common JNI code out of AudioTrack" into tm-dev am: f0cc0532 am: c0f6ac3d

parents 20712b65 c0f6ac3d
Loading
Loading
Loading
Loading
+8 −39
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "android_media_AudioFormat.h"
#include "android_media_AudioTrackCallback.h"
#include "android_media_DeviceCallback.h"
#include "android_media_JNIUtils.h"
#include "android_media_MediaMetricsJNI.h"
#include "android_media_PlaybackParams.h"
#include "android_media_VolumeShaper.h"
@@ -82,7 +83,7 @@ class AudioTrackCallbackImpl : public AudioTrack::IAudioTrackCallback {
    AudioTrackCallbackImpl(jclass audioTrackClass, jobject audioTrackWeakRef, bool isOffload)
          : mIsOffload(isOffload)
    {
      const auto env = getJNIEnv();
      const auto env = getJNIEnvOrDie();
      mAudioTrackClass = (jclass)env->NewGlobalRef(audioTrackClass);
      // we use a weak reference so the AudioTrack object can be garbage collected.
      mAudioTrackWeakRef = env->NewGlobalRef(audioTrackWeakRef);
@@ -92,7 +93,7 @@ class AudioTrackCallbackImpl : public AudioTrack::IAudioTrackCallback {
    AudioTrackCallbackImpl(const AudioTrackCallbackImpl&) = delete;
    AudioTrackCallbackImpl& operator=(const AudioTrackCallbackImpl&) = delete;
    ~AudioTrackCallbackImpl() {
        const auto env = getJNIEnv();
        const auto env = getJNIEnvOrDie();
        env->DeleteGlobalRef(mAudioTrackClass);
        env->DeleteGlobalRef(mAudioTrackWeakRef);
    }
@@ -129,16 +130,9 @@ class AudioTrackCallbackImpl : public AudioTrack::IAudioTrackCallback {
  protected:
    jobject     mAudioTrackWeakRef;
  private:
     JNIEnv* getJNIEnv() {
          auto jni = AndroidRuntime::getJNIEnv();
          if (jni == nullptr) {
              LOG_ALWAYS_FATAL("AudioTrackCallback thread JNI reference is null");
          }
          return jni;
     }

     void postEvent(int event, int arg = 0) {
        auto env = getJNIEnv();
        auto env = getJNIEnvOrDie();
        env->CallStaticVoidMethod(
                mAudioTrackClass,
                javaAudioTrackFields.postNativeEventInJava,
@@ -216,7 +210,6 @@ public:
    static void initCheckOrDie(JNIEnv *env) { (void)getIds(env); }
};

static Mutex sLock;

// ----------------------------------------------------------------------------
#define DEFAULT_OUTPUT_SAMPLE_RATE   44100
@@ -235,32 +228,6 @@ sp<IMemory> allocSharedMem(int sizeInBytes) {
    }
    return sp<MemoryBase>::make(heap, 0, sizeInBytes);
}
// TODO(b/218351957) move somewhere?
template<typename T>
sp<T> getFieldSp(JNIEnv* env, jobject thiz, jfieldID id)
{
    // make these fields atomic longs on the java side
    Mutex::Autolock l(sLock);
    return sp<T>::fromExisting(reinterpret_cast<T*>(env->GetLongField(thiz, id)));
}

// This (semantically) should only be called on AudioTrack creation and release
template <typename T>
sp<T> setFieldSp(JNIEnv* env, jobject thiz, const sp<T>& at, jfieldID id)
{
    Mutex::Autolock l(sLock);
    // I don't think this synchronization actually prevents a race
    // We can still invalidate under our feet in release
    sp<T> old = sp<T>::fromExisting(reinterpret_cast<T*>(env->GetLongField(thiz, id)));
    if (at.get()) {
        at->incStrong((void*)setFieldSp<T>);
    }
    if (old != 0) {
        old->decStrong((void*)setFieldSp<T>);
    }
    env->SetLongField(thiz, id, (jlong)at.get());
    return old;
}

sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz) {
    return getFieldSp<AudioTrack>(env, thiz, javaAudioTrackFields.nativeTrackInJavaObj);
@@ -268,8 +235,9 @@ sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz) {

} // anonymous
// ----------------------------------------------------------------------------
// For MediaSync
sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
    return getFieldSp<AudioTrack>(env, audioTrackObj, javaAudioTrackFields.nativeTrackInJavaObj);
    return getAudioTrack(env, audioTrackObj);
}

// ----------------------------------------------------------------------------
@@ -524,8 +492,9 @@ native_init_failure:
    if (nSession != NULL) {
        env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
    }
    env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);

    setFieldSp(env, thiz, sp<AudioTrack>{}, javaAudioTrackFields.nativeTrackInJavaObj);
    setFieldSp(env, thiz, sp<AudioTrackJniStorage>{}, javaAudioTrackFields.jniData);
    // lpTrack goes out of scope, so reference count drops to zero
    return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT 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 <mutex>

#include <android_runtime/AndroidRuntime.h>
#include <log/log_main.h>
#include <utils/RefBase.h>

namespace android {

// TODO (b/218351957) remove static lock
// This lock is intentionally static, it is local to each TU which is
// responsible for a single Java class.
static std::mutex sFieldSpLock;

// getFieldSp and setFieldSp are used to logically represent an owning reference
// to a native object from across the JNI. The data (underlying ptr) is stored
// in a field in the Java object as a long. Setting a Java field to a sp
// involves incrementing the reference count to prevent object destruction.
// Resetting the field decrements the reference count to avoid memory leaks.

template <typename T>
sp<T> getFieldSp(JNIEnv* env, jobject thiz, jfieldID id) {
    const std::lock_guard l{sFieldSpLock};
    return sp<T>::fromExisting(reinterpret_cast<T*>(env->GetLongField(thiz, id)));
}

template <typename T>
sp<T> setFieldSp(JNIEnv* env, jobject thiz, const sp<T>& newSp, jfieldID id) {
    const std::lock_guard l{sFieldSpLock};
    sp<T> old = sp<T>::fromExisting(reinterpret_cast<T*>(env->GetLongField(thiz, id)));
    if (newSp) {
        newSp->incStrong((void*)setFieldSp<T>);
    }
    if (old) {
        old->decStrong((void*)setFieldSp<T>);
    }
    env->SetLongField(thiz, id, (jlong)newSp.get());
    return old;
}

inline JNIEnv* getJNIEnvOrDie() {
    const auto env = AndroidRuntime::getJNIEnv();
    LOG_ALWAYS_FATAL_IF(env == nullptr,
                        "Thread JNI reference is null. Thread not prepared for Java.");
    return env;
}


} // namespace android