1 /*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <cstring>
17
18 #include <android/log.h>
19 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
20
21 #include "JavaSourceProxy.h"
22
23 static const char* TAG = "JavaSourceProxy";
24 static const char* sClassNameAudioSource = "org/hyphonate/megaaudio/player/AudioSource";
25
26 JavaVM* sJVM;
27
28 jmethodID JavaSourceProxy::sMidInit;
29 jmethodID JavaSourceProxy::sMidStart;
30 jmethodID JavaSourceProxy::sMidStop;
31 jmethodID JavaSourceProxy::sMidReset;
32 jmethodID JavaSourceProxy::sMidPull;
33
initJni(JNIEnv * env)34 void JavaSourceProxy::initJni(JNIEnv *env) {
35 env->GetJavaVM(&sJVM);
36
37 jclass clsAudioSource = env->FindClass(sClassNameAudioSource);
38
39 sMidInit = env->GetMethodID(clsAudioSource, "init", "(II)V");
40 sMidStart = env->GetMethodID(clsAudioSource, "start", "()V");
41 sMidStop = env->GetMethodID(clsAudioSource, "stop", "()V");
42 sMidReset = env->GetMethodID(clsAudioSource, "reset", "()V");
43 sMidPull = env->GetMethodID(clsAudioSource, "pull", "([FII)I");
44 }
45
JavaSourceProxy(jobject sourceObj)46 JavaSourceProxy::JavaSourceProxy(jobject sourceObj)
47 : mSourceObj(nullptr),
48 mJavaBuffer(nullptr),
49 mIsJVMAttached(false) {
50 // Get the local JNI env
51 JNIEnv * env = attachToJVM();
52 mSourceObj = env->NewGlobalRef(sourceObj);
53 detachFromJVM();
54 }
55
~JavaSourceProxy()56 JavaSourceProxy::~JavaSourceProxy() {
57 // Get the local JNI env
58 JNIEnv * env = attachToJVM();
59 env->DeleteGlobalRef(mSourceObj);
60 env->DeleteGlobalRef(mJavaBuffer);
61 detachFromJVM();
62 }
63
attachToJVM()64 JNIEnv * JavaSourceProxy::attachToJVM() {
65 // Get the local JNI env
66 JNIEnv * env;
67 int getEnvStat = sJVM->GetEnv((void **)&env, JNI_VERSION_1_6);
68
69 if (getEnvStat == JNI_EDETACHED) {
70 /*int rs = */sJVM->AttachCurrentThread(&env, NULL);
71 mIsJVMAttached = true;
72 }
73
74 return env;
75 }
76
detachFromJVM()77 void JavaSourceProxy::detachFromJVM() {
78 if (mIsJVMAttached) {
79 sJVM->DetachCurrentThread();
80 }
81 }
82
init(int numFrames,int numChans)83 void JavaSourceProxy::init(int numFrames, int numChans) {
84 JNIEnv * env = attachToJVM();
85
86 mJavaBuffer = env->NewFloatArray(numFrames * numChans);
87 mJavaBuffer = (jfloatArray)env->NewGlobalRef(mJavaBuffer);
88
89 detachFromJVM();
90 }
91
start()92 void JavaSourceProxy::start() {
93 JNIEnv * env = attachToJVM();
94 env->CallVoidMethod(mSourceObj, sMidStart);
95 detachFromJVM();
96 }
97
stop()98 void JavaSourceProxy::stop() {
99 JNIEnv * env = attachToJVM();
100 env->CallVoidMethod(mSourceObj, sMidStop);
101 detachFromJVM();
102 }
103
reset()104 void JavaSourceProxy::reset() {
105 JNIEnv * env = attachToJVM();
106 env->CallVoidMethod(mSourceObj, sMidReset);
107 detachFromJVM();
108 }
109
pull(float * buffer,int numFrames,int numChans)110 int JavaSourceProxy::pull(float* buffer, int numFrames, int numChans) {
111 JNIEnv * env = attachToJVM();
112
113 int numFilledFrames = env->CallIntMethod(mSourceObj, sMidPull, mJavaBuffer, numFrames, numChans);
114 memcpy(buffer,
115 env->GetFloatArrayElements(mJavaBuffer, 0),
116 (numFilledFrames * numChans) * sizeof(float));
117
118 detachFromJVM();
119
120 return numFilledFrames;
121 }
122
123 extern "C" {
124 JNIEXPORT void JNICALL
Java_org_hyphonate_megaaudio_player_JavaSourceProxy_initN(JNIEnv * env,jclass clazz)125 Java_org_hyphonate_megaaudio_player_JavaSourceProxy_initN(JNIEnv *env, jclass clazz) {
126 JavaSourceProxy::initJni(env);
127 }
128
129 JNIEXPORT jlong JNICALL
Java_org_hyphonate_megaaudio_player_JavaSourceProxy_allocNativeSource(JNIEnv * env,jclass clazz,jobject javaSource)130 Java_org_hyphonate_megaaudio_player_JavaSourceProxy_allocNativeSource(JNIEnv *env, jclass clazz, jobject javaSource) {
131 return (jlong)(new JavaSourceProxy(javaSource));
132 }
133
134 } // extern "C"
135