1 /**
2  * Copyright (C) 2022 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 
17 #define LOG_TAG "libimsmediajni"
18 
19 #include <assert.h>
20 #include <utils/Log.h>
21 #include <binder/Parcel.h>
22 #include <android_os_Parcel.h>
23 #include <nativehelper/JNIHelp.h>
24 #include <MediaManagerFactory.h>
25 #include <VideoManager.h>
26 #include <ImsMediaVideoUtil.h>
27 #include <ImsMediaTrace.h>
28 #include <android/native_window_jni.h>
29 #include <android/asset_manager_jni.h>
30 
31 #define IMS_MEDIA_JNI_VERSION JNI_VERSION_1_4
32 
33 static const char* gClassPath = "com/android/telephony/imsmedia/JNIImsMediaService";
34 
35 static JavaVM* gJVM = nullptr;
36 static jclass gClass_JNIImsMediaService = nullptr;
37 static jmethodID gMethod_sendData2Java = nullptr;
38 AAssetManager* gpAssetManager = nullptr;
39 
GetJavaVM()40 JavaVM* GetJavaVM()
41 {
42     return gJVM;
43 }
44 
SendData2Java(int sessionId,const android::Parcel & objParcel)45 static int SendData2Java(int sessionId, const android::Parcel& objParcel)
46 {
47     JNIEnv* env;
48 
49     if ((gClass_JNIImsMediaService == nullptr) || (gMethod_sendData2Java == nullptr))
50     {
51         ALOGE(0, "SendData2Java: Method is null", 0, 0, 0);
52         return 0;
53     }
54 
55     JavaVM* jvm = GetJavaVM();
56 
57     if (jvm->AttachCurrentThread(&env, nullptr) != JNI_OK)
58     {
59         ALOGE(0, "SendData2Java: AttachCurrentThread fail", 0, 0, 0);
60         return 0;
61     }
62 
63     jbyteArray baData = env->NewByteArray(objParcel.dataSize());
64     jbyte* pBuffer = env->GetByteArrayElements(baData, nullptr);
65 
66     if (pBuffer != nullptr)
67     {
68         memcpy(pBuffer, objParcel.data(), objParcel.dataSize());
69         env->ReleaseByteArrayElements(baData, pBuffer, 0);
70         env->CallStaticIntMethod(
71                 gClass_JNIImsMediaService, gMethod_sendData2Java, sessionId, baData);
72     }
73 
74     env->DeleteLocalRef(baData);
75 
76     return 1;
77 }
78 
setAudioThreadPriority(int threadId)79 void setAudioThreadPriority(int threadId)
80 {
81     JNIEnv* env = nullptr;
82     JavaVM* jvm = GetJavaVM();
83 
84     if (gClass_JNIImsMediaService == nullptr)
85     {
86         IMLOGE0("gClass_JNIImsMediaService is null");
87         return;
88     }
89 
90     if (jvm == nullptr || jvm->AttachCurrentThread(&env, nullptr) != JNI_OK)
91     {
92         IMLOGE0("setAudioThreadPriority: AttachCurrentThread fail");
93         return;
94     }
95 
96     if (env == nullptr)
97     {
98         IMLOGE0("env is null");
99         return;
100     }
101 
102     jmethodID gMethod_setAudioThreadPriority =
103             env->GetStaticMethodID(gClass_JNIImsMediaService, "setAudioThreadPriority", "(I)V");
104 
105     if (gMethod_setAudioThreadPriority == nullptr)
106     {
107         IMLOGE0("setAudioThreadPriority: GetStaticMethodID gMethod_setAudioThreadPriority failed");
108         return;
109     }
110 
111     env->CallStaticIntMethod(gClass_JNIImsMediaService, gMethod_setAudioThreadPriority, threadId);
112 }
113 
JNIImsMediaService_getInterface(JNIEnv *,jobject,jint mediatype)114 static jlong JNIImsMediaService_getInterface(
115         JNIEnv* /* env */, jobject /* object */, jint mediatype)
116 {
117     ALOGD("JNIImsMediaService_getInterface: type[%d]", mediatype);
118     BaseManager* manager = nullptr;
119     manager = MediaManagerFactory::getInterface(mediatype);
120     if (manager != nullptr)
121     {
122         manager->setCallback(SendData2Java);
123     }
124 
125     return static_cast<jlong>(reinterpret_cast<long>(manager));
126 }
127 
JNIImsMediaService_sendMessage(JNIEnv * env,jobject,jlong nativeObj,jint sessionId,jbyteArray baData)128 static void JNIImsMediaService_sendMessage(
129         JNIEnv* env, jobject, jlong nativeObj, jint sessionId, jbyteArray baData)
130 {
131     BaseManager* manager = reinterpret_cast<BaseManager*>(nativeObj);
132     android::Parcel parcel;
133     jbyte* pBuff = env->GetByteArrayElements(baData, nullptr);
134     int nBuffSize = env->GetArrayLength(baData);
135     parcel.setData(reinterpret_cast<const uint8_t*>(pBuff), nBuffSize);
136     parcel.setDataPosition(0);
137 
138     if (manager)
139     {
140         manager->sendMessage(sessionId, parcel);
141     }
142 
143     env->ReleaseByteArrayElements(baData, pBuff, 0);
144 }
145 
JNIImsMediaService_setPreviewSurface(JNIEnv * env,jobject,jlong nativeObj,jint sessionId,jobject surface)146 static void JNIImsMediaService_setPreviewSurface(
147         JNIEnv* env, jobject, jlong nativeObj, jint sessionId, jobject surface)
148 {
149     VideoManager* manager = reinterpret_cast<VideoManager*>(nativeObj);
150 
151     if (manager != nullptr)
152     {
153         manager->setPreviewSurface(sessionId, ANativeWindow_fromSurface(env, surface));
154     }
155 }
156 
JNIImsMediaService_setDisplaySurface(JNIEnv * env,jobject,jlong nativeObj,jint sessionId,jobject surface)157 static void JNIImsMediaService_setDisplaySurface(
158         JNIEnv* env, jobject, jlong nativeObj, jint sessionId, jobject surface)
159 {
160     VideoManager* manager = reinterpret_cast<VideoManager*>(nativeObj);
161 
162     if (manager != nullptr)
163     {
164         manager->setDisplaySurface(sessionId, ANativeWindow_fromSurface(env, surface));
165     }
166 }
167 
JNIImsMediaUtil_generateSPROP(JNIEnv * env,jobject,jbyteArray baData)168 static jstring JNIImsMediaUtil_generateSPROP(JNIEnv* env, jobject, jbyteArray baData)
169 {
170     android::Parcel parcel;
171     jbyte* pBuff = env->GetByteArrayElements(baData, nullptr);
172     int nBuffSize = env->GetArrayLength(baData);
173     parcel.setData(reinterpret_cast<const uint8_t*>(pBuff), nBuffSize);
174     parcel.setDataPosition(0);
175 
176     VideoConfig videoConfig;
177     videoConfig.readFromParcel(&parcel);
178     env->ReleaseByteArrayElements(baData, pBuff, 0);
179     ALOGE("[GenerateVideoSprop] Profile[%d] level[%d]", videoConfig.getCodecProfile(),
180             videoConfig.getCodecLevel());
181 
182     char* sprop = ImsMediaVideoUtil::GenerateVideoSprop(&videoConfig);
183     jstring str = nullptr;
184     if (sprop != nullptr)
185     {
186         str = env->NewStringUTF(sprop);
187         free(sprop);
188     }
189 
190     return str;
191 }
192 
SetAssetManager(JNIEnv * env,jobject,jobject jobjAssetManager)193 static void SetAssetManager(JNIEnv* env, jobject, jobject jobjAssetManager)
194 {
195     gpAssetManager = AAssetManager_fromJava(env, jobjAssetManager);
196     ALOGD("[SetAssetManager] Asset manager has been set in JNI");
197 }
198 
JNIImsMediaService_setLogMode(JNIEnv *,jobject,jint logMode,jint debugLogMode)199 static void JNIImsMediaService_setLogMode(JNIEnv*, jobject, jint logMode, jint debugLogMode)
200 {
201     ImsMediaTrace::IMSetLogMode(logMode);
202     ImsMediaTrace::IMSetDebugLogMode(debugLogMode);
203 }
204 
205 static JNINativeMethod gMethods[] = {
206         {"getInterface", "(I)J", (void*)JNIImsMediaService_getInterface},
207         {"sendMessage", "(JI[B)V", (void*)JNIImsMediaService_sendMessage},
208         {"setPreviewSurface", "(JILandroid/view/Surface;)V",
209                 (void*)JNIImsMediaService_setPreviewSurface},
210         {"setDisplaySurface", "(JILandroid/view/Surface;)V",
211                 (void*)JNIImsMediaService_setDisplaySurface},
212         {"generateSprop", "([B)Ljava/lang/String;", (void*)JNIImsMediaUtil_generateSPROP},
213         {"setAssetManager", "(Landroid/content/res/AssetManager;)V", (void*)SetAssetManager},
214         {"setLogMode", "(II)V", (void*)JNIImsMediaService_setLogMode},
215 };
216 
ImsMediaServiceJni_OnLoad(JavaVM * vm,JNIEnv * env)217 jint ImsMediaServiceJni_OnLoad(JavaVM* vm, JNIEnv* env)
218 {
219     gJVM = vm;
220 
221     jclass _jclassImsMediaService = env->FindClass(gClassPath);
222 
223     if (_jclassImsMediaService == nullptr)
224     {
225         ALOGE("ImsMediaServiceJni_OnLoad :: FindClass failed");
226         return -1;
227     }
228 
229     gClass_JNIImsMediaService = reinterpret_cast<jclass>(env->NewGlobalRef(_jclassImsMediaService));
230 
231     if (gClass_JNIImsMediaService == nullptr)
232     {
233         ALOGE("ImsMediaServiceJni_OnLoad :: FindClass failed2");
234         return -1;
235     }
236 
237     if (jniRegisterNativeMethods(env, gClassPath, gMethods, NELEM(gMethods)) < 0)
238     {
239         ALOGE("ImsMediaServiceJni_OnLoad: RegisterNatives failed");
240         return -1;
241     }
242 
243     gMethod_sendData2Java =
244             env->GetStaticMethodID(gClass_JNIImsMediaService, "sendData2Java", "(I[B)I");
245 
246     if (gMethod_sendData2Java == nullptr)
247     {
248         ALOGE("ImsMediaServiceJni_OnLoad: GetStaticMethodID failed");
249         return -1;
250     }
251 
252     return IMS_MEDIA_JNI_VERSION;
253 }
254