From 825c21585e9615ae3b332b9bbd1dfbd497f27c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 5 Oct 2019 14:47:23 +0200 Subject: [PATCH] Pass Discovered Hosts to Kotlin on Android --- android/app/src/main/cpp/chiaki-jni.c | 109 ++++++++++++++++-- .../chiaki/discovery/DiscoveryManager.kt | 16 ++- .../java/com/metallic/chiaki/lib/Chiaki.kt | 13 ++- 3 files changed, 125 insertions(+), 13 deletions(-) diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index eb4fb8f..b32f3c6 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -36,6 +36,10 @@ #define LOG_TAG "Chiaki" #define JNI_VERSION JNI_VERSION_1_6 +#define BASE_PACKAGE "com/metallic/chiaki/lib" + +#define E (*env) + static void log_cb_android(ChiakiLogLevel level, const char *msg, void *user) { int prio; @@ -78,6 +82,18 @@ static char *strdup_jni(const char *str) return r; } +static jobject jnistr_from_ascii(JNIEnv *env, const char *str) +{ + if(!str) + return NULL; + char *s = strdup_jni(str); + if(!s) + return NULL; + jobject r = E->NewStringUTF(env, s); + free(s); + return r; +} + static ChiakiLog global_log; static JavaVM *global_vm; @@ -91,8 +107,6 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) return JNI_VERSION; } -#define E (*env) - JNIEXPORT jstring JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_errorCodeToString(JNIEnv *env, jobject obj, jint value) { return E->NewStringUTF(env, chiaki_error_string((ChiakiErrorCode)value)); @@ -192,7 +206,7 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J jstring host_string = E->GetObjectField(env, connect_info_obj, E->GetFieldID(env, connect_info_class, "host", "Ljava/lang/String;")); jbyteArray regist_key_array = E->GetObjectField(env, connect_info_obj, E->GetFieldID(env, connect_info_class, "registKey", "[B")); jbyteArray morning_array = E->GetObjectField(env, connect_info_obj, E->GetFieldID(env, connect_info_class, "morning", "[B")); - jobject connect_video_profile_obj = E->GetObjectField(env, connect_info_obj, E->GetFieldID(env, connect_info_class, "videoProfile", "Lcom/metallic/chiaki/lib/ConnectVideoProfile;")); + jobject connect_video_profile_obj = E->GetObjectField(env, connect_info_obj, E->GetFieldID(env, connect_info_class, "videoProfile", "L"BASE_PACKAGE"/ConnectVideoProfile;")); jclass connect_video_profile_class = E->GetObjectClass(env, connect_video_profile_obj); ChiakiConnectInfo connect_info; @@ -266,12 +280,12 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J } session->java_session = E->NewGlobalRef(env, java_session); - session->java_session_class = E->GetObjectClass(env, session->java_session); + session->java_session_class = E->NewGlobalRef(env, E->GetObjectClass(env, session->java_session)); session->java_session_event_connected_meth = E->GetMethodID(env, session->java_session_class, "eventConnected", "()V"); 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"); - jclass controller_state_class = E->FindClass(env, "com/metallic/chiaki/lib/ControllerState"); + jclass controller_state_class = E->FindClass(env, BASE_PACKAGE"/ControllerState"); session->java_controller_state_buttons = E->GetFieldID(env, controller_state_class, "buttons", "I"); session->java_controller_state_l2_state = E->GetFieldID(env, controller_state_class, "l2State", "B"); session->java_controller_state_r2_state = E->GetFieldID(env, controller_state_class, "r2State", "B"); @@ -305,6 +319,7 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionFree(JNI android_chiaki_audio_decoder_fini(&session->audio_decoder); android_chiaki_audio_output_free(session->audio_output); E->DeleteGlobalRef(env, session->java_session); + E->DeleteGlobalRef(env, session->java_session_class); CHIAKI_LOGI(&global_log, "JNI Session has quit"); } @@ -361,13 +376,61 @@ typedef struct android_discovery_service_t { ChiakiDiscoveryService service; jobject java_service; + jclass java_service_class; + jmethodID java_service_hosts_updated_meth; + + jclass host_class; + jmethodID host_ctor; + jobject host_state_unknown; + jobject host_state_ready; + jobject host_state_standby; } AndroidDiscoveryService; static void android_discovery_service_cb(ChiakiDiscoveryHost *hosts, size_t hosts_count, void *user) { AndroidDiscoveryService *service = user; - // TODO - CHIAKI_LOGD(&global_log, "Discovered %d hosts", (int)hosts_count); + + JNIEnv *env = attach_thread_jni(); + if(!env) + return; + + jobjectArray r = E->NewObjectArray(env, hosts_count, service->host_class, NULL); + + for(size_t i=0; istate) + { + case CHIAKI_DISCOVERY_HOST_STATE_STANDBY: + state = service->host_state_standby; + break; + case CHIAKI_DISCOVERY_HOST_STATE_READY: + state = service->host_state_ready; + break; + default: + state = service->host_state_unknown; + break; + } + + jobject o = E->NewObject(env, service->host_class, service->host_ctor, + state, + host->host_request_port, + jnistr_from_ascii(env, host->host_addr), + jnistr_from_ascii(env, host->system_version), + jnistr_from_ascii(env, host->device_discovery_protocol_version), + jnistr_from_ascii(env, host->host_name), + jnistr_from_ascii(env, host->host_type), + jnistr_from_ascii(env, host->host_id), + jnistr_from_ascii(env, host->running_app_titleid), + jnistr_from_ascii(env, host->running_app_name)); + + E->SetObjectArrayElement(env, r, i, o); + } + + E->CallVoidMethod(env, service->java_service, service->java_service_hosts_updated_meth, r); + + (*global_vm)->DetachCurrentThread(global_vm); } static ChiakiErrorCode sockaddr_from_java(JNIEnv *env, jobject /*InetSocketAddress*/ sockaddr_obj, struct sockaddr **addr, size_t *addr_size) @@ -444,13 +507,39 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_discoveryServic } service->java_service = E->NewGlobalRef(env, java_service); - // TODO: service->whatever = get id for callback method + service->java_service_class = E->GetObjectClass(env, service->java_service); + service->java_service_hosts_updated_meth = E->GetMethodID(env, service->java_service_class, "hostsUpdated", "([L"BASE_PACKAGE"/DiscoveryHost;)V"); + + service->host_class = E->NewGlobalRef(env, E->FindClass(env, BASE_PACKAGE"/DiscoveryHost")); + service->host_ctor = E->GetMethodID(env, service->host_class, "", "(" + "L"BASE_PACKAGE"/DiscoveryHost$State;" + "S" // hostRequestPort: UShort + "Ljava/lang/String;" // hostAddr: String?, + "Ljava/lang/String;" // systemVersion: String?, + "Ljava/lang/String;" // deviceDiscoveryProtocolVersion: String?, + "Ljava/lang/String;" // hostName: String?, + "Ljava/lang/String;" // hostType: String?, + "Ljava/lang/String;" // hostId: String?, + "Ljava/lang/String;" // runningAppTitleid: String?, + "Ljava/lang/String;" // runningAppName: String? + ")V"); + + jclass host_state_class = E->FindClass(env, BASE_PACKAGE"/DiscoveryHost$State"); + service->host_state_unknown = E->NewGlobalRef(env, E->GetStaticObjectField(env, host_state_class, E->GetStaticFieldID(env, host_state_class, "UNKNOWN", "L"BASE_PACKAGE"/DiscoveryHost$State;"))); + service->host_state_standby = E->NewGlobalRef(env, E->GetStaticObjectField(env, host_state_class, E->GetStaticFieldID(env, host_state_class, "STANDBY", "L"BASE_PACKAGE"/DiscoveryHost$State;"))); + service->host_state_ready = E->NewGlobalRef(env, E->GetStaticObjectField(env, host_state_class, E->GetStaticFieldID(env, host_state_class, "READY", "L"BASE_PACKAGE"/DiscoveryHost$State;"))); + err = chiaki_discovery_service_init(&service->service, &options, &global_log); if(err != CHIAKI_ERR_SUCCESS) { CHIAKI_LOGE(&global_log, "Failed to create discovery service (JNI)"); E->DeleteGlobalRef(env, service->java_service); + E->DeleteGlobalRef(env, service->host_state_unknown); + E->DeleteGlobalRef(env, service->host_state_standby); + E->DeleteGlobalRef(env, service->host_state_ready); + E->DeleteGlobalRef(env, service->host_class); + free(service); goto beach; } @@ -467,5 +556,9 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_discoveryServic return; chiaki_discovery_service_fini(&service->service); E->DeleteGlobalRef(env, service->java_service); + E->DeleteGlobalRef(env, service->host_state_unknown); + E->DeleteGlobalRef(env, service->host_state_standby); + E->DeleteGlobalRef(env, service->host_state_ready); + E->DeleteGlobalRef(env, service->host_class); free(service); } diff --git a/android/app/src/main/java/com/metallic/chiaki/discovery/DiscoveryManager.kt b/android/app/src/main/java/com/metallic/chiaki/discovery/DiscoveryManager.kt index 082b910..8f91306 100644 --- a/android/app/src/main/java/com/metallic/chiaki/discovery/DiscoveryManager.kt +++ b/android/app/src/main/java/com/metallic/chiaki/discovery/DiscoveryManager.kt @@ -17,6 +17,8 @@ package com.metallic.chiaki.discovery +import android.util.Log +import com.metallic.chiaki.lib.CreateError import com.metallic.chiaki.lib.DiscoveryService import com.metallic.chiaki.lib.DiscoveryServiceOptions import java.net.InetSocketAddress @@ -37,10 +39,16 @@ class DiscoveryManager { if(discoveryService != null) return - // TODO: catch CreateError - discoveryService = DiscoveryService(DiscoveryServiceOptions( - HOSTS_MAX, DROP_PINGS, PING_MS, InetSocketAddress("255.255.255.255", PORT) - )) + try + { + discoveryService = DiscoveryService(DiscoveryServiceOptions( + HOSTS_MAX, DROP_PINGS, PING_MS, InetSocketAddress("255.255.255.255", PORT) + )) + } + catch(e: CreateError) + { + Log.e("DiscoveryManager", "Failed to start Discovery Service: $e") + } } fun stop() 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 8cd76e2..1f6bf29 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 android.view.Surface import kotlinx.android.parcel.Parcelize import java.lang.Exception @@ -209,7 +210,9 @@ data class DiscoveryServiceOptions( val sendAddr: InetSocketAddress ) -class DiscoveryService(options: DiscoveryServiceOptions) +class DiscoveryService( + options: DiscoveryServiceOptions, + val callback: ((hosts: List) -> Unit)? = null) { private var nativePtr: Long @@ -230,4 +233,12 @@ class DiscoveryService(options: DiscoveryServiceOptions) ChiakiNative.discoveryServiceFree(nativePtr) nativePtr = 0L } + + private fun hostsUpdated(hosts: Array) + { + val hostsList = hosts.toList() + Log.i("Chiaki", "got hosts from native: $hostsList") + callback?.let { it(hostsList) } + } + } \ No newline at end of file