diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index 770b0c0..5603244 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -9,6 +9,7 @@ #include #define LOG_TAG "Chiaki" +#define JNI_VERSION JNI_VERSION_1_6 static void log_cb_android(ChiakiLogLevel level, const char *msg, void *user) { @@ -37,15 +38,32 @@ static void log_cb_android(ChiakiLogLevel level, const char *msg, void *user) __android_log_write(prio, LOG_TAG, msg); } -ChiakiLog log_ctx; +static char *strdup_jni(const char *str) +{ + if(!str) + return NULL; + char *r = strdup(str); + if(!r) + return NULL; + for(char *c=r; *c; c++) + { + if(*c & (1 << 7)) + *c = '?'; + } + return r; +} + +static ChiakiLog global_log; +static JavaVM *global_vm; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { - chiaki_log_init(&log_ctx, CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE, log_cb_android, NULL); - CHIAKI_LOGI(&log_ctx, "Loading Chiaki Library"); + global_vm = vm; + chiaki_log_init(&global_log, CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE, log_cb_android, NULL); + CHIAKI_LOGI(&global_log, "Loading Chiaki Library"); ChiakiErrorCode err = chiaki_lib_init(); - CHIAKI_LOGI(&log_ctx, "Chiaki Library Init Result: %s\n", chiaki_error_string(err)); - return JNI_VERSION_1_2; + CHIAKI_LOGI(&global_log, "Chiaki Library Init Result: %s\n", chiaki_error_string(err)); + return JNI_VERSION; } #define E (*env) @@ -55,9 +73,68 @@ JNIEXPORT jstring JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_errorCodeToS return E->NewStringUTF(env, chiaki_error_string((ChiakiErrorCode)value)); } -JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(JNIEnv *env, jobject obj, jobject result, jobject connect_info_obj) +JNIEXPORT jstring JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_quitReasonToString(JNIEnv *env, jobject obj, jint value) { - ChiakiSession *session = NULL; + return E->NewStringUTF(env, chiaki_quit_reason_string((ChiakiQuitReason)value)); +} + +typedef struct android_chiaki_session_t +{ + ChiakiSession session; + jobject java_session; + jclass java_session_class; + jmethodID java_session_event_login_pin_request_meth; + jmethodID java_session_event_quit_meth; +} AndroidChiakiSession; + +static JNIEnv *attach_thread_jni() +{ + JNIEnv *env; + int r = (*global_vm)->GetEnv(global_vm, (void **)&env, JNI_VERSION); + if(r == JNI_OK) + return env; + + if((*global_vm)->AttachCurrentThread(global_vm, &env, NULL) == 0) + return env; + + CHIAKI_LOGE(&global_log, "Failed to get JNIEnv from JavaVM or attach"); +} + +static void android_chiaki_event_cb(ChiakiEvent *event, void *user) +{ + AndroidChiakiSession *session = user; + + JNIEnv *env = attach_thread_jni(); + if(!env) + return; + + switch(event->type) + { + case CHIAKI_EVENT_LOGIN_PIN_REQUEST: + E->CallVoidMethod(env, session->java_session, + session->java_session_event_login_pin_request_meth, + (jboolean)event->login_pin_request.pin_incorrect); + break; + case CHIAKI_EVENT_QUIT: + { + char *reason_str = strdup_jni(event->quit.reason_str); + jstring reason_str_java = E->NewStringUTF(env, reason_str ? reason_str : ""); + E->CallVoidMethod(env, session->java_session, + session->java_session_event_quit_meth, + (jint)event->quit.reason, + reason_str_java); + E->DeleteLocalRef(env, reason_str_java); + free(reason_str); + break; + } + } + + (*global_vm)->DetachCurrentThread(global_vm); +} + +JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(JNIEnv *env, jobject obj, jobject result, jobject connect_info_obj, jobject java_session) +{ + AndroidChiakiSession *session = NULL; ChiakiErrorCode err = CHIAKI_ERR_SUCCESS; char *host_str = NULL; @@ -82,7 +159,7 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J if(E->GetArrayLength(env, regist_key_array) != sizeof(connect_info.regist_key)) { - CHIAKI_LOGE(&log_ctx, "Regist Key passed from Java has invalid length"); + CHIAKI_LOGE(&global_log, "Regist Key passed from Java has invalid length"); err = CHIAKI_ERR_INVALID_DATA; goto beach; } @@ -92,7 +169,7 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J if(E->GetArrayLength(env, morning_array) != sizeof(connect_info.morning)) { - CHIAKI_LOGE(&log_ctx, "Morning passed from Java has invalid length"); + CHIAKI_LOGE(&global_log, "Morning passed from Java has invalid length"); err = CHIAKI_ERR_INVALID_DATA; goto beach; } @@ -106,14 +183,27 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J connect_info.video_profile.max_fps = (unsigned int)E->GetIntField(env, connect_video_profile_obj, E->GetFieldID(env, connect_video_profile_class, "maxFPS", "I")); connect_info.video_profile.bitrate = (unsigned int)E->GetIntField(env, connect_video_profile_obj, E->GetFieldID(env, connect_video_profile_class, "bitrate", "I")); - session = CHIAKI_NEW(ChiakiSession); + session = CHIAKI_NEW(AndroidChiakiSession); if(!session) { err = CHIAKI_ERR_MEMORY; goto beach; } - err = chiaki_session_init(session, &connect_info, &log_ctx); + err = chiaki_session_init(&session->session, &connect_info, &global_log); + + if(err != CHIAKI_ERR_SUCCESS) + { + session->java_session = NULL; + goto beach; + } + + session->java_session = E->NewGlobalRef(env, java_session); + session->java_session_class = E->GetObjectClass(env, session->java_session); + session->java_session_event_login_pin_request_meth = E->GetMethodID(env, session->java_session_class, "eventLoginPinRequest", "(Z)V"); + session->java_session_event_quit_meth = E->GetMethodID(env, session->java_session_class, "eventQuit", "(ILjava/lang/String;)V"); + + chiaki_session_set_event_cb(&session->session, android_chiaki_event_cb, session); beach: free(host_str); @@ -123,27 +213,28 @@ beach: JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionFree(JNIEnv *env, jobject obj, jlong ptr) { - ChiakiSession *session = (ChiakiSession *)ptr; + AndroidChiakiSession *session = (AndroidChiakiSession *)ptr; if(!session) return; - chiaki_session_fini(session); + E->DeleteGlobalRef(env, session->java_session); + chiaki_session_fini(&session->session); free(session); } JNIEXPORT jint JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionStart(JNIEnv *env, jobject obj, jlong ptr) { - ChiakiSession *session = (ChiakiSession *)ptr; - return chiaki_session_start(session); + AndroidChiakiSession *session = (AndroidChiakiSession *)ptr; + return chiaki_session_start(&session->session); } JNIEXPORT jint JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionStop(JNIEnv *env, jobject obj, jlong ptr) { - ChiakiSession *session = (ChiakiSession *)ptr; - return chiaki_session_stop(session); + AndroidChiakiSession *session = (AndroidChiakiSession *)ptr; + return chiaki_session_stop(&session->session); } JNIEXPORT jint JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionJoin(JNIEnv *env, jobject obj, jlong ptr) { - ChiakiSession *session = (ChiakiSession *)ptr; - return chiaki_session_join(session); + AndroidChiakiSession *session = (AndroidChiakiSession *)ptr; + return chiaki_session_join(&session->session); } diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index 0e57770..b27525e 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -1,6 +1,7 @@ package com.metallic.chiaki.lib import android.os.Parcelable +import android.util.Log import kotlinx.android.parcel.Parcelize import java.lang.Exception @@ -30,7 +31,8 @@ class ChiakiNative System.loadLibrary("chiaki-jni") } @JvmStatic external fun errorCodeToString(value: Int): String - @JvmStatic external fun sessionCreate(result: SessionCreateResult, connectInfo: ConnectInfo) + @JvmStatic external fun quitReasonToString(value: Int): String + @JvmStatic external fun sessionCreate(result: SessionCreateResult, connectInfo: ConnectInfo, javaSession: Session) @JvmStatic external fun sessionFree(ptr: Long) @JvmStatic external fun sessionStart(ptr: Long): Int @JvmStatic external fun sessionStop(ptr: Long): Int @@ -44,6 +46,15 @@ class ErrorCode(val value: Int) var isSuccess = value == 0 } +class QuitReason(val value: Int) +{ + override fun toString() = ChiakiNative.quitReasonToString(value) +} + +sealed class Event +data class LoginPinRequestEvent(val pinIncorrect: Boolean): Event() +data class QuitEvent(val reason: QuitReason, val reasonString: String): Event() + class SessionCreateError(val errorCode: ErrorCode): Exception("Failed to create Session: $errorCode") class Session(connectInfo: ConnectInfo) @@ -53,7 +64,7 @@ class Session(connectInfo: ConnectInfo) init { val result = ChiakiNative.SessionCreateResult(0, 0) - ChiakiNative.sessionCreate(result, connectInfo) + ChiakiNative.sessionCreate(result, connectInfo, this) val errorCode = ErrorCode(result.errorCode) if(!errorCode.isSuccess) throw SessionCreateError(errorCode) @@ -71,4 +82,20 @@ class Session(connectInfo: ConnectInfo) ChiakiNative.sessionFree(nativePtr) nativePtr = 0L } + + private fun event(event: Event) + { + // TODO: send to callback + Log.d("ChiakiJNI", "Got event $event") + } + + private fun eventLoginPinRequest(pinIncorrect: Boolean) + { + event(LoginPinRequestEvent(pinIncorrect)) + } + + private fun eventQuit(reasonValue: Int, reasonString: String) + { + event(QuitEvent(QuitReason(reasonValue), reasonString)) + } } \ No newline at end of file