1 /*
2  * Copyright (C) 2008 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_NDEBUG 0
18 #define LOG_TAG "JET_JNI"
19 
20 
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 
25 #include <jni.h>
26 #include <JNIHelp.h>
27 #include "core_jni_helpers.h"
28 
29 #include <utils/Log.h>
30 #include <media/JetPlayer.h>
31 
32 
33 using namespace android;
34 
35 // ----------------------------------------------------------------------------
36 static const char* const kClassPathName = "android/media/JetPlayer";
37 
38 // ----------------------------------------------------------------------------
39 struct fields_t {
40     // these fields provide access from C++ to the...
41     jclass    jetClass;              // JetPlayer java class global ref
42     jmethodID postNativeEventInJava; // java method to post events to the Java thread from native
43     jfieldID  nativePlayerInJavaObj; // stores in Java the native JetPlayer object
44 };
45 
46 static fields_t javaJetPlayerFields;
47 
48 
49 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
51 
52 /*
53  * This function is called from JetPlayer instance's render thread
54  */
55 static void
jetPlayerEventCallback(int what,int arg1=0,int arg2=0,void * javaTarget=NULL)56 jetPlayerEventCallback(int what, int arg1=0, int arg2=0, void* javaTarget = NULL)
57 {
58     JNIEnv *env = AndroidRuntime::getJNIEnv();
59     if (env) {
60         env->CallStaticVoidMethod(
61             javaJetPlayerFields.jetClass, javaJetPlayerFields.postNativeEventInJava,
62             javaTarget,
63             what, arg1, arg2);
64         if (env->ExceptionCheck()) {
65             env->ExceptionDescribe();
66             env->ExceptionClear();
67         }
68     } else {
69         ALOGE("JET jetPlayerEventCallback(): No JNI env for JET event callback, can't post event.");
70         return;
71     }
72 }
73 
74 
75 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
77 
78 static jboolean
android_media_JetPlayer_setup(JNIEnv * env,jobject thiz,jobject weak_this,jint maxTracks,jint trackBufferSize)79 android_media_JetPlayer_setup(JNIEnv *env, jobject thiz, jobject weak_this,
80     jint maxTracks, jint trackBufferSize)
81 {
82     //ALOGV("android_media_JetPlayer_setup(): entering.");
83     JetPlayer* lpJet = new JetPlayer(env->NewGlobalRef(weak_this), maxTracks, trackBufferSize);
84 
85     EAS_RESULT result = lpJet->init();
86 
87     if (result==EAS_SUCCESS) {
88         // save our newly created C++ JetPlayer in the "nativePlayerInJavaObj" field
89         // of the Java object (in mNativePlayerInJavaObj)
90         env->SetLongField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, (jlong)lpJet);
91         return JNI_TRUE;
92     } else {
93         ALOGE("android_media_JetPlayer_setup(): initialization failed with EAS error code %d", (int)result);
94         delete lpJet;
95         env->SetLongField(weak_this, javaJetPlayerFields.nativePlayerInJavaObj, 0);
96         return JNI_FALSE;
97     }
98 }
99 
100 
101 // ----------------------------------------------------------------------------
102 static void
android_media_JetPlayer_finalize(JNIEnv * env,jobject thiz)103 android_media_JetPlayer_finalize(JNIEnv *env, jobject thiz)
104 {
105     ALOGV("android_media_JetPlayer_finalize(): entering.");
106     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
107         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
108     if (lpJet != NULL) {
109         lpJet->release();
110         delete lpJet;
111     }
112 
113     ALOGV("android_media_JetPlayer_finalize(): exiting.");
114 }
115 
116 
117 // ----------------------------------------------------------------------------
118 static void
android_media_JetPlayer_release(JNIEnv * env,jobject thiz)119 android_media_JetPlayer_release(JNIEnv *env, jobject thiz)
120 {
121     android_media_JetPlayer_finalize(env, thiz);
122     env->SetLongField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, 0);
123     ALOGV("android_media_JetPlayer_release() done");
124 }
125 
126 
127 // ----------------------------------------------------------------------------
128 static jboolean
android_media_JetPlayer_loadFromFile(JNIEnv * env,jobject thiz,jstring path)129 android_media_JetPlayer_loadFromFile(JNIEnv *env, jobject thiz, jstring path)
130 {
131     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
132         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
133     if (lpJet == NULL) {
134         jniThrowException(env, "java/lang/IllegalStateException",
135             "Unable to retrieve JetPlayer pointer for openFile()");
136         return JNI_FALSE;
137     }
138 
139     // set up event callback function
140     lpJet->setEventCallback(jetPlayerEventCallback);
141 
142     const char *pathStr = env->GetStringUTFChars(path, NULL);
143     if (pathStr == NULL) {  // Out of memory
144         ALOGE("android_media_JetPlayer_openFile(): aborting, out of memory");
145         return JNI_FALSE;
146     }
147 
148     ALOGV("android_media_JetPlayer_openFile(): trying to open %s", pathStr );
149     EAS_RESULT result = lpJet->loadFromFile(pathStr);
150     env->ReleaseStringUTFChars(path, pathStr);
151 
152     if (result==EAS_SUCCESS) {
153         //ALOGV("android_media_JetPlayer_openFile(): file successfully opened");
154         return JNI_TRUE;
155     } else {
156         ALOGE("android_media_JetPlayer_openFile(): failed to open file with EAS error %d",
157             (int)result);
158         return JNI_FALSE;
159     }
160 }
161 
162 
163 // ----------------------------------------------------------------------------
164 static jboolean
android_media_JetPlayer_loadFromFileD(JNIEnv * env,jobject thiz,jobject fileDescriptor,jlong offset,jlong length)165 android_media_JetPlayer_loadFromFileD(JNIEnv *env, jobject thiz,
166     jobject fileDescriptor, jlong offset, jlong length)
167 {
168     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
169         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
170     if (lpJet == NULL) {
171         jniThrowException(env, "java/lang/IllegalStateException",
172             "Unable to retrieve JetPlayer pointer for openFile()");
173         return JNI_FALSE;
174     }
175 
176     // set up event callback function
177     lpJet->setEventCallback(jetPlayerEventCallback);
178 
179     ALOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" );
180     EAS_RESULT result = lpJet->loadFromFD(jniGetFDFromFileDescriptor(env, fileDescriptor),
181         (long long)offset, (long long)length); // cast params to types used by EAS_FILE
182 
183     if (result==EAS_SUCCESS) {
184         ALOGV("android_media_JetPlayer_openFileDescr(): file successfully opened");
185         return JNI_TRUE;
186     } else {
187         ALOGE("android_media_JetPlayer_openFileDescr(): failed to open file with EAS error %d",
188             (int)result);
189         return JNI_FALSE;
190     }
191 }
192 
193 
194 // ----------------------------------------------------------------------------
195 static jboolean
android_media_JetPlayer_closeFile(JNIEnv * env,jobject thiz)196 android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz)
197 {
198     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
199         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
200     if (lpJet == NULL) {
201         jniThrowException(env, "java/lang/IllegalStateException",
202             "Unable to retrieve JetPlayer pointer for closeFile()");
203         return JNI_FALSE;
204     }
205 
206     if (lpJet->closeFile()==EAS_SUCCESS) {
207         //ALOGV("android_media_JetPlayer_closeFile(): file successfully closed");
208         return JNI_TRUE;
209     } else {
210         ALOGE("android_media_JetPlayer_closeFile(): failed to close file");
211         return JNI_FALSE;
212     }
213 }
214 
215 
216 // ----------------------------------------------------------------------------
217 static jboolean
android_media_JetPlayer_play(JNIEnv * env,jobject thiz)218 android_media_JetPlayer_play(JNIEnv *env, jobject thiz)
219 {
220     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
221         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
222     if (lpJet == NULL) {
223         jniThrowException(env, "java/lang/IllegalStateException",
224             "Unable to retrieve JetPlayer pointer for play()");
225         return JNI_FALSE;
226     }
227 
228     EAS_RESULT result = lpJet->play();
229     if (result==EAS_SUCCESS) {
230         //ALOGV("android_media_JetPlayer_play(): play successful");
231         return JNI_TRUE;
232     } else {
233         ALOGE("android_media_JetPlayer_play(): failed to play with EAS error code %ld",
234             result);
235         return JNI_FALSE;
236     }
237 }
238 
239 
240 // ----------------------------------------------------------------------------
241 static jboolean
android_media_JetPlayer_pause(JNIEnv * env,jobject thiz)242 android_media_JetPlayer_pause(JNIEnv *env, jobject thiz)
243 {
244     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
245         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
246     if (lpJet == NULL) {
247         jniThrowException(env, "java/lang/IllegalStateException",
248             "Unable to retrieve JetPlayer pointer for pause()");
249         return JNI_FALSE;
250     }
251 
252     EAS_RESULT result = lpJet->pause();
253     if (result==EAS_SUCCESS) {
254         //ALOGV("android_media_JetPlayer_pause(): pause successful");
255         return JNI_TRUE;
256     } else {
257         if (result==EAS_ERROR_QUEUE_IS_EMPTY) {
258             ALOGV("android_media_JetPlayer_pause(): paused with an empty queue");
259             return JNI_TRUE;
260         } else
261             ALOGE("android_media_JetPlayer_pause(): failed to pause with EAS error code %ld",
262                 result);
263         return JNI_FALSE;
264     }
265 }
266 
267 
268 // ----------------------------------------------------------------------------
269 static jboolean
android_media_JetPlayer_queueSegment(JNIEnv * env,jobject thiz,jint segmentNum,jint libNum,jint repeatCount,jint transpose,jint muteFlags,jbyte userID)270 android_media_JetPlayer_queueSegment(JNIEnv *env, jobject thiz,
271         jint segmentNum, jint libNum, jint repeatCount, jint transpose, jint muteFlags,
272         jbyte userID)
273 {
274     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
275         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
276     if (lpJet == NULL) {
277         jniThrowException(env, "java/lang/IllegalStateException",
278             "Unable to retrieve JetPlayer pointer for queueSegment()");
279         return JNI_FALSE;
280     }
281 
282     EAS_RESULT result
283         = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
284     if (result==EAS_SUCCESS) {
285         //ALOGV("android_media_JetPlayer_queueSegment(): segment successfully queued");
286         return JNI_TRUE;
287     } else {
288         ALOGE("android_media_JetPlayer_queueSegment(): failed with EAS error code %ld",
289             result);
290         return JNI_FALSE;
291     }
292 }
293 
294 
295 // ----------------------------------------------------------------------------
296 static jboolean
android_media_JetPlayer_queueSegmentMuteArray(JNIEnv * env,jobject thiz,jint segmentNum,jint libNum,jint repeatCount,jint transpose,jbooleanArray muteArray,jbyte userID)297 android_media_JetPlayer_queueSegmentMuteArray(JNIEnv *env, jobject thiz,
298         jint segmentNum, jint libNum, jint repeatCount, jint transpose, jbooleanArray muteArray,
299         jbyte userID)
300 {
301     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
302         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
303     if (lpJet == NULL) {
304         jniThrowException(env, "java/lang/IllegalStateException",
305             "Unable to retrieve JetPlayer pointer for queueSegmentMuteArray()");
306         return JNI_FALSE;
307     }
308 
309     EAS_RESULT result=EAS_FAILURE;
310 
311     jboolean *muteTracks = NULL;
312     muteTracks = env->GetBooleanArrayElements(muteArray, NULL);
313     if (muteTracks == NULL) {
314         ALOGE("android_media_JetPlayer_queueSegment(): failed to read track mute mask.");
315         return JNI_FALSE;
316     }
317 
318     EAS_U32 muteMask=0;
319     int maxTracks = lpJet->getMaxTracks();
320     for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) {
321         if (muteTracks[maxTracks-1-trackIndex]==JNI_TRUE)
322             muteMask = (muteMask << 1) | 0x00000001;
323         else
324             muteMask = muteMask << 1;
325     }
326     //ALOGV("android_media_JetPlayer_queueSegmentMuteArray(): FINAL mute mask =0x%08lX", mask);
327 
328     result = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteMask, userID);
329 
330     env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0);
331     if (result==EAS_SUCCESS) {
332         //ALOGV("android_media_JetPlayer_queueSegmentMuteArray(): segment successfully queued");
333         return JNI_TRUE;
334     } else {
335         ALOGE("android_media_JetPlayer_queueSegmentMuteArray(): failed with EAS error code %ld",
336             result);
337         return JNI_FALSE;
338     }
339 }
340 
341 
342 // ----------------------------------------------------------------------------
343 static jboolean
android_media_JetPlayer_setMuteFlags(JNIEnv * env,jobject thiz,jint muteFlags,jboolean bSync)344 android_media_JetPlayer_setMuteFlags(JNIEnv *env, jobject thiz,
345          jint muteFlags /*unsigned?*/, jboolean bSync)
346 {
347     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
348         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
349     if (lpJet == NULL) {
350         jniThrowException(env, "java/lang/IllegalStateException",
351             "Unable to retrieve JetPlayer pointer for setMuteFlags()");
352         return JNI_FALSE;
353     }
354 
355     EAS_RESULT result;
356     result = lpJet->setMuteFlags(muteFlags, bSync==JNI_TRUE ? true : false);
357     if (result==EAS_SUCCESS) {
358         //ALOGV("android_media_JetPlayer_setMuteFlags(): mute flags successfully updated");
359         return JNI_TRUE;
360     } else {
361         ALOGE("android_media_JetPlayer_setMuteFlags(): failed with EAS error code %ld", result);
362         return JNI_FALSE;
363     }
364 }
365 
366 
367 // ----------------------------------------------------------------------------
368 static jboolean
android_media_JetPlayer_setMuteArray(JNIEnv * env,jobject thiz,jbooleanArray muteArray,jboolean bSync)369 android_media_JetPlayer_setMuteArray(JNIEnv *env, jobject thiz,
370         jbooleanArray muteArray, jboolean bSync)
371 {
372     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
373         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
374     if (lpJet == NULL) {
375         jniThrowException(env, "java/lang/IllegalStateException",
376             "Unable to retrieve JetPlayer pointer for setMuteArray()");
377         return JNI_FALSE;
378     }
379 
380     EAS_RESULT result=EAS_FAILURE;
381 
382     jboolean *muteTracks = NULL;
383     muteTracks = env->GetBooleanArrayElements(muteArray, NULL);
384     if (muteTracks == NULL) {
385         ALOGE("android_media_JetPlayer_setMuteArray(): failed to read track mute mask.");
386         return JNI_FALSE;
387     }
388 
389     EAS_U32 muteMask=0;
390     int maxTracks = lpJet->getMaxTracks();
391     for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) {
392         if (muteTracks[maxTracks-1-trackIndex]==JNI_TRUE)
393             muteMask = (muteMask << 1) | 0x00000001;
394         else
395             muteMask = muteMask << 1;
396     }
397     //ALOGV("android_media_JetPlayer_setMuteArray(): FINAL mute mask =0x%08lX", muteMask);
398 
399     result = lpJet->setMuteFlags(muteMask, bSync==JNI_TRUE ? true : false);
400 
401     env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0);
402     if (result==EAS_SUCCESS) {
403         //ALOGV("android_media_JetPlayer_setMuteArray(): mute flags successfully updated");
404         return JNI_TRUE;
405     } else {
406         ALOGE("android_media_JetPlayer_setMuteArray(): \
407             failed to update mute flags with EAS error code %ld", result);
408         return JNI_FALSE;
409     }
410 }
411 
412 
413 // ----------------------------------------------------------------------------
414 static jboolean
android_media_JetPlayer_setMuteFlag(JNIEnv * env,jobject thiz,jint trackId,jboolean muteFlag,jboolean bSync)415 android_media_JetPlayer_setMuteFlag(JNIEnv *env, jobject thiz,
416          jint trackId, jboolean muteFlag, jboolean bSync)
417 {
418     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
419         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
420     if (lpJet == NULL) {
421         jniThrowException(env, "java/lang/IllegalStateException",
422             "Unable to retrieve JetPlayer pointer for setMuteFlag()");
423         return JNI_FALSE;
424     }
425 
426     EAS_RESULT result;
427     result = lpJet->setMuteFlag(trackId,
428         muteFlag==JNI_TRUE ? true : false, bSync==JNI_TRUE ? true : false);
429     if (result==EAS_SUCCESS) {
430         //ALOGV("android_media_JetPlayer_setMuteFlag(): mute flag successfully updated for track %d", trackId);
431         return JNI_TRUE;
432     } else {
433         ALOGE("android_media_JetPlayer_setMuteFlag(): failed to update mute flag for track %d with EAS error code %ld",
434                 trackId, result);
435         return JNI_FALSE;
436     }
437 }
438 
439 
440 // ----------------------------------------------------------------------------
441 static jboolean
android_media_JetPlayer_triggerClip(JNIEnv * env,jobject thiz,jint clipId)442 android_media_JetPlayer_triggerClip(JNIEnv *env, jobject thiz, jint clipId)
443 {
444     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
445         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
446     if (lpJet == NULL) {
447         jniThrowException(env, "java/lang/IllegalStateException",
448             "Unable to retrieve JetPlayer pointer for triggerClip()");
449         return JNI_FALSE;
450     }
451 
452     EAS_RESULT result;
453     result = lpJet->triggerClip(clipId);
454     if (result==EAS_SUCCESS) {
455         //ALOGV("android_media_JetPlayer_triggerClip(): triggerClip successful for clip %d", clipId);
456         return JNI_TRUE;
457     } else {
458         ALOGE("android_media_JetPlayer_triggerClip(): triggerClip for clip %d failed with EAS error code %ld",
459                 clipId, result);
460         return JNI_FALSE;
461     }
462 }
463 
464 
465 // ----------------------------------------------------------------------------
466 static jboolean
android_media_JetPlayer_clearQueue(JNIEnv * env,jobject thiz)467 android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz)
468 {
469     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
470         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
471     if (lpJet == NULL) {
472         jniThrowException(env, "java/lang/IllegalStateException",
473             "Unable to retrieve JetPlayer pointer for clearQueue()");
474         return JNI_FALSE;
475     }
476 
477     EAS_RESULT result = lpJet->clearQueue();
478     if (result==EAS_SUCCESS) {
479         //ALOGV("android_media_JetPlayer_clearQueue(): clearQueue successful");
480         return JNI_TRUE;
481     } else {
482         ALOGE("android_media_JetPlayer_clearQueue(): clearQueue failed with EAS error code %ld",
483                 result);
484         return JNI_FALSE;
485     }
486 }
487 
488 
489 // ----------------------------------------------------------------------------
490 // ----------------------------------------------------------------------------
491 static const JNINativeMethod gMethods[] = {
492     // name,               signature,               funcPtr
493     {"native_setup",       "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup},
494     {"native_finalize",    "()V",                   (void *)android_media_JetPlayer_finalize},
495     {"native_release",     "()V",                   (void *)android_media_JetPlayer_release},
496     {"native_loadJetFromFile",
497                            "(Ljava/lang/String;)Z", (void *)android_media_JetPlayer_loadFromFile},
498     {"native_loadJetFromFileD", "(Ljava/io/FileDescriptor;JJ)Z",
499                                                     (void *)android_media_JetPlayer_loadFromFileD},
500     {"native_closeJetFile","()Z",                   (void *)android_media_JetPlayer_closeFile},
501     {"native_playJet",     "()Z",                   (void *)android_media_JetPlayer_play},
502     {"native_pauseJet",    "()Z",                   (void *)android_media_JetPlayer_pause},
503     {"native_queueJetSegment",
504                            "(IIIIIB)Z",             (void *)android_media_JetPlayer_queueSegment},
505     {"native_queueJetSegmentMuteArray",
506                            "(IIII[ZB)Z",     (void *)android_media_JetPlayer_queueSegmentMuteArray},
507     {"native_setMuteFlags","(IZ)Z",                 (void *)android_media_JetPlayer_setMuteFlags},
508     {"native_setMuteArray","([ZZ)Z",                (void *)android_media_JetPlayer_setMuteArray},
509     {"native_setMuteFlag", "(IZZ)Z",                (void *)android_media_JetPlayer_setMuteFlag},
510     {"native_triggerClip", "(I)Z",                  (void *)android_media_JetPlayer_triggerClip},
511     {"native_clearQueue",  "()Z",                   (void *)android_media_JetPlayer_clearQueue},
512 };
513 
514 #define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj"
515 #define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative"
516 
517 
register_android_media_JetPlayer(JNIEnv * env)518 int register_android_media_JetPlayer(JNIEnv *env)
519 {
520     javaJetPlayerFields.jetClass = NULL;
521     javaJetPlayerFields.postNativeEventInJava = NULL;
522     javaJetPlayerFields.nativePlayerInJavaObj = NULL;
523 
524     // Get the JetPlayer java class
525     jclass jetPlayerClass = FindClassOrDie(env, kClassPathName);
526     javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass);
527 
528     // Get the mNativePlayerInJavaObj variable field
529     javaJetPlayerFields.nativePlayerInJavaObj = GetFieldIDOrDie(env,
530             jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J");
531 
532     // Get the callback to post events from this native code to Java
533     javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
534             javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME,
535             "(Ljava/lang/Object;III)V");
536 
537     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
538 }
539