mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-19 21:13:12 -07:00
Add Android File Log
This commit is contained in:
parent
bd02acb5a0
commit
84cdbe41dc
8 changed files with 270 additions and 107 deletions
|
@ -5,6 +5,8 @@ set(CMAKE_CXX_STANDARD 14)
|
||||||
|
|
||||||
add_library(chiaki-jni SHARED
|
add_library(chiaki-jni SHARED
|
||||||
src/main/cpp/chiaki-jni.c
|
src/main/cpp/chiaki-jni.c
|
||||||
|
src/main/cpp/log.h
|
||||||
|
src/main/cpp/log.c
|
||||||
src/main/cpp/video-decoder.h
|
src/main/cpp/video-decoder.h
|
||||||
src/main/cpp/video-decoder.c
|
src/main/cpp/video-decoder.c
|
||||||
src/main/cpp/audio-decoder.h
|
src/main/cpp/audio-decoder.h
|
||||||
|
|
|
@ -33,41 +33,8 @@
|
||||||
#include "video-decoder.h"
|
#include "video-decoder.h"
|
||||||
#include "audio-decoder.h"
|
#include "audio-decoder.h"
|
||||||
#include "audio-output.h"
|
#include "audio-output.h"
|
||||||
|
#include "log.h"
|
||||||
#define LOG_TAG "Chiaki"
|
#include "chiaki-jni.h"
|
||||||
#define JNI_VERSION JNI_VERSION_1_6
|
|
||||||
|
|
||||||
#define BASE_PACKAGE "com/metallic/chiaki/lib"
|
|
||||||
#define JNI_FCN(name) Java_com_metallic_chiaki_lib_ChiakiNative_##name
|
|
||||||
|
|
||||||
#define E (*env)
|
|
||||||
|
|
||||||
static void log_cb_android(ChiakiLogLevel level, const char *msg, void *user)
|
|
||||||
{
|
|
||||||
int prio;
|
|
||||||
switch(level)
|
|
||||||
{
|
|
||||||
case CHIAKI_LOG_DEBUG:
|
|
||||||
prio = ANDROID_LOG_DEBUG;
|
|
||||||
break;
|
|
||||||
case CHIAKI_LOG_VERBOSE:
|
|
||||||
prio = ANDROID_LOG_VERBOSE;
|
|
||||||
break;
|
|
||||||
case CHIAKI_LOG_INFO:
|
|
||||||
prio = ANDROID_LOG_INFO;
|
|
||||||
break;
|
|
||||||
case CHIAKI_LOG_WARNING:
|
|
||||||
prio = ANDROID_LOG_ERROR;
|
|
||||||
break;
|
|
||||||
case CHIAKI_LOG_ERROR:
|
|
||||||
prio = ANDROID_LOG_ERROR;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
prio = ANDROID_LOG_INFO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
__android_log_write(prio, LOG_TAG, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *strdup_jni(const char *str)
|
static char *strdup_jni(const char *str)
|
||||||
{
|
{
|
||||||
|
@ -84,7 +51,7 @@ static char *strdup_jni(const char *str)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jobject jnistr_from_ascii(JNIEnv *env, const char *str)
|
jobject jnistr_from_ascii(JNIEnv *env, const char *str)
|
||||||
{
|
{
|
||||||
if(!str)
|
if(!str)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -121,18 +88,33 @@ static jobject get_kotlin_global_object(JNIEnv *env, const char *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
static ChiakiLog global_log;
|
static ChiakiLog global_log;
|
||||||
static JavaVM *global_vm;
|
JavaVM *global_vm;
|
||||||
|
|
||||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
|
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||||
{
|
{
|
||||||
global_vm = vm;
|
global_vm = vm;
|
||||||
chiaki_log_init(&global_log, CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE, log_cb_android, NULL);
|
|
||||||
|
android_chiaki_file_log_init(&global_log, CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE, NULL);
|
||||||
CHIAKI_LOGI(&global_log, "Loading Chiaki Library");
|
CHIAKI_LOGI(&global_log, "Loading Chiaki Library");
|
||||||
ChiakiErrorCode err = chiaki_lib_init();
|
ChiakiErrorCode err = chiaki_lib_init();
|
||||||
CHIAKI_LOGI(&global_log, "Chiaki Library Init Result: %s\n", chiaki_error_string(err));
|
CHIAKI_LOGI(&global_log, "Chiaki Library Init Result: %s\n", chiaki_error_string(err));
|
||||||
return JNI_VERSION;
|
return JNI_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL JNI_FCN(errorCodeToString)(JNIEnv *env, jobject obj, jint value)
|
JNIEXPORT jstring JNICALL JNI_FCN(errorCodeToString)(JNIEnv *env, jobject obj, jint value)
|
||||||
{
|
{
|
||||||
return E->NewStringUTF(env, chiaki_error_string((ChiakiErrorCode)value));
|
return E->NewStringUTF(env, chiaki_error_string((ChiakiErrorCode)value));
|
||||||
|
@ -160,6 +142,7 @@ JNIEXPORT jobject JNICALL JNI_FCN(videoProfilePreset)(JNIEnv *env, jobject obj,
|
||||||
typedef struct android_chiaki_session_t
|
typedef struct android_chiaki_session_t
|
||||||
{
|
{
|
||||||
ChiakiSession session;
|
ChiakiSession session;
|
||||||
|
ChiakiLog *log;
|
||||||
jobject java_session;
|
jobject java_session;
|
||||||
jclass java_session_class;
|
jclass java_session_class;
|
||||||
jmethodID java_session_event_connected_meth;
|
jmethodID java_session_event_connected_meth;
|
||||||
|
@ -178,54 +161,6 @@ typedef struct android_chiaki_session_t
|
||||||
void *audio_output;
|
void *audio_output;
|
||||||
} AndroidChiakiSession;
|
} 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");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct android_chiaki_log_t
|
|
||||||
{
|
|
||||||
jobject java_log;
|
|
||||||
jmethodID java_log_meth;
|
|
||||||
ChiakiLog log;
|
|
||||||
} AndroidChiakiLog;
|
|
||||||
|
|
||||||
static void android_chiaki_log_cb(ChiakiLogLevel level, const char *msg, void *user)
|
|
||||||
{
|
|
||||||
log_cb_android(level, msg, NULL);
|
|
||||||
|
|
||||||
AndroidChiakiLog *log = user;
|
|
||||||
JNIEnv *env = attach_thread_jni();
|
|
||||||
if(!env)
|
|
||||||
return;
|
|
||||||
E->CallVoidMethod(env, log->java_log, log->java_log_meth, (jint)level, jnistr_from_ascii(env, msg));
|
|
||||||
(*global_vm)->DetachCurrentThread(global_vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void android_chiaki_log_init(AndroidChiakiLog *log, JNIEnv *env, jobject java_log)
|
|
||||||
{
|
|
||||||
log->java_log = E->NewGlobalRef(env, java_log);
|
|
||||||
jclass log_class = E->GetObjectClass(env, log->java_log);
|
|
||||||
log->java_log_meth = E->GetMethodID(env, log_class, "log", "(ILjava/lang/String;)V");
|
|
||||||
log->log.level_mask = (uint32_t)E->GetIntField(env, log->java_log, E->GetFieldID(env, log_class, "levelMask", "I"));
|
|
||||||
log->log.cb = android_chiaki_log_cb;
|
|
||||||
log->log.user = log;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void android_chiaki_log_fini(AndroidChiakiLog *log, JNIEnv *env)
|
|
||||||
{
|
|
||||||
E->DeleteGlobalRef(env, log->java_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void android_chiaki_event_cb(ChiakiEvent *event, void *user)
|
static void android_chiaki_event_cb(ChiakiEvent *event, void *user)
|
||||||
{
|
{
|
||||||
AndroidChiakiSession *session = user;
|
AndroidChiakiSession *session = user;
|
||||||
|
@ -263,9 +198,15 @@ static void android_chiaki_event_cb(ChiakiEvent *event, void *user)
|
||||||
(*global_vm)->DetachCurrentThread(global_vm);
|
(*global_vm)->DetachCurrentThread(global_vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject result, jobject connect_info_obj, jobject java_session)
|
JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject result, jobject connect_info_obj, jstring log_file_str, jboolean log_verbose, jobject java_session)
|
||||||
{
|
{
|
||||||
AndroidChiakiSession *session = NULL;
|
AndroidChiakiSession *session = NULL;
|
||||||
|
ChiakiLog *log = malloc(sizeof(ChiakiLog));
|
||||||
|
const char *log_file = log_file_str ? E->GetStringUTFChars(env, log_file_str, NULL) : NULL;
|
||||||
|
android_chiaki_file_log_init(log, log_verbose ? CHIAKI_LOG_ALL : (CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE), log_file);
|
||||||
|
if(log_file)
|
||||||
|
E->ReleaseStringUTFChars(env, log_file_str, log_file);
|
||||||
|
|
||||||
ChiakiErrorCode err = CHIAKI_ERR_SUCCESS;
|
ChiakiErrorCode err = CHIAKI_ERR_SUCCESS;
|
||||||
char *host_str = NULL;
|
char *host_str = NULL;
|
||||||
|
|
||||||
|
@ -290,7 +231,7 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject
|
||||||
|
|
||||||
if(E->GetArrayLength(env, regist_key_array) != sizeof(connect_info.regist_key))
|
if(E->GetArrayLength(env, regist_key_array) != sizeof(connect_info.regist_key))
|
||||||
{
|
{
|
||||||
CHIAKI_LOGE(&global_log, "Regist Key passed from Java has invalid length");
|
CHIAKI_LOGE(log, "Regist Key passed from Java has invalid length");
|
||||||
err = CHIAKI_ERR_INVALID_DATA;
|
err = CHIAKI_ERR_INVALID_DATA;
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +241,7 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject
|
||||||
|
|
||||||
if(E->GetArrayLength(env, morning_array) != sizeof(connect_info.morning))
|
if(E->GetArrayLength(env, morning_array) != sizeof(connect_info.morning))
|
||||||
{
|
{
|
||||||
CHIAKI_LOGE(&global_log, "Morning passed from Java has invalid length");
|
CHIAKI_LOGE(log, "Morning passed from Java has invalid length");
|
||||||
err = CHIAKI_ERR_INVALID_DATA;
|
err = CHIAKI_ERR_INVALID_DATA;
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +261,8 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
memset(session, 0, sizeof(AndroidChiakiSession));
|
memset(session, 0, sizeof(AndroidChiakiSession));
|
||||||
err = android_chiaki_video_decoder_init(&session->video_decoder, &global_log);
|
session->log = log;
|
||||||
|
err = android_chiaki_video_decoder_init(&session->video_decoder, log);
|
||||||
if(err != CHIAKI_ERR_SUCCESS)
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
free(session);
|
free(session);
|
||||||
|
@ -328,7 +270,7 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = android_chiaki_audio_decoder_init(&session->audio_decoder, &global_log);
|
err = android_chiaki_audio_decoder_init(&session->audio_decoder, log);
|
||||||
if(err != CHIAKI_ERR_SUCCESS)
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
android_chiaki_video_decoder_fini(&session->video_decoder);
|
android_chiaki_video_decoder_fini(&session->video_decoder);
|
||||||
|
@ -337,14 +279,14 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
session->audio_output = android_chiaki_audio_output_new(&global_log);
|
session->audio_output = android_chiaki_audio_output_new(log);
|
||||||
|
|
||||||
android_chiaki_audio_decoder_set_cb(&session->audio_decoder, android_chiaki_audio_output_settings, android_chiaki_audio_output_frame, session->audio_output);
|
android_chiaki_audio_decoder_set_cb(&session->audio_decoder, android_chiaki_audio_output_settings, android_chiaki_audio_output_frame, session->audio_output);
|
||||||
|
|
||||||
err = chiaki_session_init(&session->session, &connect_info, &global_log);
|
err = chiaki_session_init(&session->session, &connect_info, log);
|
||||||
if(err != CHIAKI_ERR_SUCCESS)
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
CHIAKI_LOGE(&global_log, "JNI ChiakiSession failed to init");
|
CHIAKI_LOGE(log, "JNI ChiakiSession failed to init");
|
||||||
android_chiaki_video_decoder_fini(&session->video_decoder);
|
android_chiaki_video_decoder_fini(&session->video_decoder);
|
||||||
android_chiaki_audio_decoder_fini(&session->audio_decoder);
|
android_chiaki_audio_decoder_fini(&session->audio_decoder);
|
||||||
android_chiaki_audio_output_free(session->audio_output);
|
android_chiaki_audio_output_free(session->audio_output);
|
||||||
|
@ -376,6 +318,12 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject
|
||||||
chiaki_session_set_audio_sink(&session->session, &audio_sink);
|
chiaki_session_set_audio_sink(&session->session, &audio_sink);
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
|
if(!session && log)
|
||||||
|
{
|
||||||
|
android_chiaki_file_log_fini(log);
|
||||||
|
free(log);
|
||||||
|
}
|
||||||
|
|
||||||
free(host_str);
|
free(host_str);
|
||||||
E->SetIntField(env, result, E->GetFieldID(env, result_class, "errorCode", "I"), (jint)err);
|
E->SetIntField(env, result, E->GetFieldID(env, result_class, "errorCode", "I"), (jint)err);
|
||||||
E->SetLongField(env, result, E->GetFieldID(env, result_class, "ptr", "J"), (jlong)session);
|
E->SetLongField(env, result, E->GetFieldID(env, result_class, "ptr", "J"), (jlong)session);
|
||||||
|
@ -384,9 +332,9 @@ beach:
|
||||||
JNIEXPORT void JNICALL JNI_FCN(sessionFree)(JNIEnv *env, jobject obj, jlong ptr)
|
JNIEXPORT void JNICALL JNI_FCN(sessionFree)(JNIEnv *env, jobject obj, jlong ptr)
|
||||||
{
|
{
|
||||||
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
||||||
CHIAKI_LOGI(&global_log, "Shutting down JNI Session");
|
|
||||||
if(!session)
|
if(!session)
|
||||||
return;
|
return;
|
||||||
|
CHIAKI_LOGI(session->log, "Shutting down JNI Session");
|
||||||
chiaki_session_fini(&session->session);
|
chiaki_session_fini(&session->session);
|
||||||
free(session);
|
free(session);
|
||||||
android_chiaki_video_decoder_fini(&session->video_decoder);
|
android_chiaki_video_decoder_fini(&session->video_decoder);
|
||||||
|
@ -400,21 +348,21 @@ JNIEXPORT void JNICALL JNI_FCN(sessionFree)(JNIEnv *env, jobject obj, jlong ptr)
|
||||||
JNIEXPORT jint JNICALL JNI_FCN(sessionStart)(JNIEnv *env, jobject obj, jlong ptr)
|
JNIEXPORT jint JNICALL JNI_FCN(sessionStart)(JNIEnv *env, jobject obj, jlong ptr)
|
||||||
{
|
{
|
||||||
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
||||||
CHIAKI_LOGI(&global_log, "Start JNI Session");
|
CHIAKI_LOGI(session->log, "Start JNI Session");
|
||||||
return chiaki_session_start(&session->session);
|
return chiaki_session_start(&session->session);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL JNI_FCN(sessionStop)(JNIEnv *env, jobject obj, jlong ptr)
|
JNIEXPORT jint JNICALL JNI_FCN(sessionStop)(JNIEnv *env, jobject obj, jlong ptr)
|
||||||
{
|
{
|
||||||
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
||||||
CHIAKI_LOGI(&global_log, "Stop JNI Session");
|
CHIAKI_LOGI(session->log, "Stop JNI Session");
|
||||||
return chiaki_session_stop(&session->session);
|
return chiaki_session_stop(&session->session);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL JNI_FCN(sessionJoin)(JNIEnv *env, jobject obj, jlong ptr)
|
JNIEXPORT jint JNICALL JNI_FCN(sessionJoin)(JNIEnv *env, jobject obj, jlong ptr)
|
||||||
{
|
{
|
||||||
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
|
||||||
CHIAKI_LOGI(&global_log, "Join JNI Session");
|
CHIAKI_LOGI(session->log, "Join JNI Session");
|
||||||
return chiaki_session_join(&session->session);
|
return chiaki_session_join(&session->session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +599,7 @@ JNIEXPORT jint JNICALL JNI_FCN(discoveryServiceWakeup)(JNIEnv *env, jobject obj,
|
||||||
|
|
||||||
typedef struct android_chiaki_regist_t
|
typedef struct android_chiaki_regist_t
|
||||||
{
|
{
|
||||||
AndroidChiakiLog log;
|
AndroidChiakiJNILog log;
|
||||||
ChiakiRegist regist;
|
ChiakiRegist regist;
|
||||||
|
|
||||||
jobject java_regist;
|
jobject java_regist;
|
||||||
|
@ -709,7 +657,7 @@ static void android_chiaki_regist_cb(ChiakiRegistEvent *event, void *user)
|
||||||
|
|
||||||
static void android_chiaki_regist_fini_partial(JNIEnv *env, AndroidChiakiRegist *regist)
|
static void android_chiaki_regist_fini_partial(JNIEnv *env, AndroidChiakiRegist *regist)
|
||||||
{
|
{
|
||||||
android_chiaki_log_fini(®ist->log, env);
|
android_chiaki_jni_log_fini(®ist->log, env);
|
||||||
E->DeleteGlobalRef(env, regist->java_regist);
|
E->DeleteGlobalRef(env, regist->java_regist);
|
||||||
E->DeleteGlobalRef(env, regist->java_regist_event_canceled);
|
E->DeleteGlobalRef(env, regist->java_regist_event_canceled);
|
||||||
E->DeleteGlobalRef(env, regist->java_regist_event_failed);
|
E->DeleteGlobalRef(env, regist->java_regist_event_failed);
|
||||||
|
@ -728,7 +676,7 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
android_chiaki_log_init(®ist->log, env, log_obj);
|
android_chiaki_jni_log_init(®ist->log, env, log_obj);
|
||||||
|
|
||||||
regist->java_regist = E->NewGlobalRef(env, java_regist);
|
regist->java_regist = E->NewGlobalRef(env, java_regist);
|
||||||
regist->java_regist_event_meth = E->GetMethodID(env, E->GetObjectClass(env, regist->java_regist), "event", "(L"BASE_PACKAGE"/RegistEvent;)V");
|
regist->java_regist_event_meth = E->GetMethodID(env, E->GetObjectClass(env, regist->java_regist), "event", "(L"BASE_PACKAGE"/RegistEvent;)V");
|
||||||
|
|
33
android/app/src/main/cpp/chiaki-jni.h
Normal file
33
android/app/src/main/cpp/chiaki-jni.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_JNI_H
|
||||||
|
#define CHIAKI_JNI_H
|
||||||
|
|
||||||
|
#define JNI_VERSION JNI_VERSION_1_6
|
||||||
|
|
||||||
|
#define BASE_PACKAGE "com/metallic/chiaki/lib"
|
||||||
|
#define JNI_FCN(name) Java_com_metallic_chiaki_lib_ChiakiNative_##name
|
||||||
|
|
||||||
|
#define E (*env)
|
||||||
|
|
||||||
|
JNIEnv *attach_thread_jni();
|
||||||
|
jobject jnistr_from_ascii(JNIEnv *env, const char *str);
|
||||||
|
|
||||||
|
extern JavaVM *global_vm;
|
||||||
|
|
||||||
|
#endif
|
142
android/app/src/main/cpp/log.c
Normal file
142
android/app/src/main/cpp/log.c
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "chiaki-jni.h"
|
||||||
|
|
||||||
|
#define LOG_TAG "Chiaki"
|
||||||
|
|
||||||
|
void log_cb_android(ChiakiLogLevel level, const char *msg, void *user)
|
||||||
|
{
|
||||||
|
int prio;
|
||||||
|
switch(level)
|
||||||
|
{
|
||||||
|
case CHIAKI_LOG_DEBUG:
|
||||||
|
prio = ANDROID_LOG_DEBUG;
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_VERBOSE:
|
||||||
|
prio = ANDROID_LOG_VERBOSE;
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_INFO:
|
||||||
|
prio = ANDROID_LOG_INFO;
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_WARNING:
|
||||||
|
prio = ANDROID_LOG_ERROR;
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_ERROR:
|
||||||
|
prio = ANDROID_LOG_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prio = ANDROID_LOG_INFO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
__android_log_write(prio, LOG_TAG, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_cb_android_file(ChiakiLogLevel level, const char *msg, void *user)
|
||||||
|
{
|
||||||
|
log_cb_android(level, msg, user);
|
||||||
|
FILE *f = user;
|
||||||
|
if(!f)
|
||||||
|
return;
|
||||||
|
switch(level)
|
||||||
|
{
|
||||||
|
case CHIAKI_LOG_DEBUG:
|
||||||
|
fwrite("[D] ", 4, 1, f);
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_VERBOSE:
|
||||||
|
fwrite("[V] ", 4, 1, f);
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_INFO:
|
||||||
|
fwrite("[I] ", 4, 1, f);
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_WARNING:
|
||||||
|
fwrite("[W] ", 4, 1, f);
|
||||||
|
break;
|
||||||
|
case CHIAKI_LOG_ERROR:
|
||||||
|
fwrite("[E] ", 4, 1, f);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fwrite("[?] ", 4, 1, f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fwrite(msg, strlen(msg), 1, f);
|
||||||
|
fwrite("\n", 1, 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiakiErrorCode android_chiaki_file_log_init(ChiakiLog *log, uint32_t level, const char *file)
|
||||||
|
{
|
||||||
|
chiaki_log_init(log, level, log_cb_android, NULL);
|
||||||
|
if(file)
|
||||||
|
{
|
||||||
|
FILE *f = fopen(file, "w+");
|
||||||
|
if(!f)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(log, "Failed to open log file %s for writing: %s", file, strerror(errno));
|
||||||
|
return CHIAKI_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
log->user = f;
|
||||||
|
log->cb = log_cb_android_file;
|
||||||
|
}
|
||||||
|
return CHIAKI_ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void android_chiaki_file_log_fini(ChiakiLog *log)
|
||||||
|
{
|
||||||
|
if(log->user)
|
||||||
|
{
|
||||||
|
FILE *f = log->user;
|
||||||
|
fclose(f);
|
||||||
|
log->user = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void android_chiaki_log_cb(ChiakiLogLevel level, const char *msg, void *user)
|
||||||
|
{
|
||||||
|
log_cb_android(level, msg, NULL);
|
||||||
|
|
||||||
|
AndroidChiakiJNILog *log = user;
|
||||||
|
JNIEnv *env = attach_thread_jni();
|
||||||
|
if(!env)
|
||||||
|
return;
|
||||||
|
E->CallVoidMethod(env, log->java_log, log->java_log_meth, (jint)level, jnistr_from_ascii(env, msg));
|
||||||
|
(*global_vm)->DetachCurrentThread(global_vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void android_chiaki_jni_log_init(AndroidChiakiJNILog *log, JNIEnv *env, jobject java_log)
|
||||||
|
{
|
||||||
|
log->java_log = E->NewGlobalRef(env, java_log);
|
||||||
|
jclass log_class = E->GetObjectClass(env, log->java_log);
|
||||||
|
log->java_log_meth = E->GetMethodID(env, log_class, "log", "(ILjava/lang/String;)V");
|
||||||
|
log->log.level_mask = (uint32_t)E->GetIntField(env, log->java_log, E->GetFieldID(env, log_class, "levelMask", "I"));
|
||||||
|
log->log.cb = android_chiaki_log_cb;
|
||||||
|
log->log.user = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
void android_chiaki_jni_log_fini(AndroidChiakiJNILog *log, JNIEnv *env)
|
||||||
|
{
|
||||||
|
E->DeleteGlobalRef(env, log->java_log);
|
||||||
|
}
|
38
android/app/src/main/cpp/log.h
Normal file
38
android/app/src/main/cpp/log.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_JNI_LOG_H
|
||||||
|
#define CHIAKI_JNI_LOG_H
|
||||||
|
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
typedef struct android_jni_chiaki_log_t
|
||||||
|
{
|
||||||
|
jobject java_log;
|
||||||
|
jmethodID java_log_meth;
|
||||||
|
ChiakiLog log;
|
||||||
|
} AndroidChiakiJNILog;
|
||||||
|
|
||||||
|
ChiakiErrorCode android_chiaki_file_log_init(ChiakiLog *log, uint32_t level, const char *file);
|
||||||
|
void android_chiaki_file_log_fini(ChiakiLog *log);
|
||||||
|
|
||||||
|
void android_chiaki_jni_log_init(AndroidChiakiJNILog *log, JNIEnv *env, jobject java_log);
|
||||||
|
void android_chiaki_jni_log_fini(AndroidChiakiJNILog *log, JNIEnv *env);
|
||||||
|
|
||||||
|
#endif
|
|
@ -58,7 +58,7 @@ private class ChiakiNative
|
||||||
@JvmStatic external fun quitReasonToString(value: Int): String
|
@JvmStatic external fun quitReasonToString(value: Int): String
|
||||||
@JvmStatic external fun quitReasonIsStopped(value: Int): Boolean
|
@JvmStatic external fun quitReasonIsStopped(value: Int): Boolean
|
||||||
@JvmStatic external fun videoProfilePreset(resolutionPreset: Int, fpsPreset: Int): ConnectVideoProfile
|
@JvmStatic external fun videoProfilePreset(resolutionPreset: Int, fpsPreset: Int): ConnectVideoProfile
|
||||||
@JvmStatic external fun sessionCreate(result: CreateResult, connectInfo: ConnectInfo, javaSession: Session)
|
@JvmStatic external fun sessionCreate(result: CreateResult, connectInfo: ConnectInfo, logFile: String?, logVerbose: Boolean, javaSession: Session)
|
||||||
@JvmStatic external fun sessionFree(ptr: Long)
|
@JvmStatic external fun sessionFree(ptr: Long)
|
||||||
@JvmStatic external fun sessionStart(ptr: Long): Int
|
@JvmStatic external fun sessionStart(ptr: Long): Int
|
||||||
@JvmStatic external fun sessionStop(ptr: Long): Int
|
@JvmStatic external fun sessionStop(ptr: Long): Int
|
||||||
|
@ -179,7 +179,7 @@ data class QuitEvent(val reason: QuitReason, val reasonString: String?): Event()
|
||||||
|
|
||||||
class CreateError(val errorCode: ErrorCode): Exception("Failed to create a native object: $errorCode")
|
class CreateError(val errorCode: ErrorCode): Exception("Failed to create a native object: $errorCode")
|
||||||
|
|
||||||
class Session(connectInfo: ConnectInfo)
|
class Session(connectInfo: ConnectInfo, logFile: String?, logVerbose: Boolean)
|
||||||
{
|
{
|
||||||
interface EventCallback
|
interface EventCallback
|
||||||
{
|
{
|
||||||
|
@ -192,7 +192,7 @@ class Session(connectInfo: ConnectInfo)
|
||||||
init
|
init
|
||||||
{
|
{
|
||||||
val result = ChiakiNative.CreateResult(0, 0)
|
val result = ChiakiNative.CreateResult(0, 0)
|
||||||
ChiakiNative.sessionCreate(result, connectInfo, this)
|
ChiakiNative.sessionCreate(result, connectInfo, logFile, logVerbose, this)
|
||||||
val errorCode = ErrorCode(result.errorCode)
|
val errorCode = ErrorCode(result.errorCode)
|
||||||
if(!errorCode.isSuccess)
|
if(!errorCode.isSuccess)
|
||||||
throw CreateError(errorCode)
|
throw CreateError(errorCode)
|
||||||
|
|
|
@ -32,7 +32,7 @@ data class StreamStateCreateError(val error: CreateError): StreamState()
|
||||||
data class StreamStateQuit(val reason: QuitReason, val reasonString: String?): StreamState()
|
data class StreamStateQuit(val reason: QuitReason, val reasonString: String?): StreamState()
|
||||||
data class StreamStateLoginPinRequest(val pinIncorrect: Boolean): StreamState()
|
data class StreamStateLoginPinRequest(val pinIncorrect: Boolean): StreamState()
|
||||||
|
|
||||||
class StreamSession(val connectInfo: ConnectInfo, val input: StreamInput)
|
class StreamSession(val connectInfo: ConnectInfo, val logVerbose: Boolean, val input: StreamInput)
|
||||||
{
|
{
|
||||||
var session: Session? = null
|
var session: Session? = null
|
||||||
private set
|
private set
|
||||||
|
@ -69,7 +69,7 @@ class StreamSession(val connectInfo: ConnectInfo, val input: StreamInput)
|
||||||
return
|
return
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
val session = Session(connectInfo)
|
val session = Session(connectInfo, null, logVerbose) // TODO: log file
|
||||||
_state.value = StreamStateConnecting
|
_state.value = StreamStateConnecting
|
||||||
session.eventCallback = this::eventCallback
|
session.eventCallback = this::eventCallback
|
||||||
session.start()
|
session.start()
|
||||||
|
|
|
@ -29,7 +29,7 @@ class StreamViewModel(val preferences: Preferences, val connectInfo: ConnectInfo
|
||||||
{
|
{
|
||||||
private var _session: StreamSession? = null
|
private var _session: StreamSession? = null
|
||||||
val input = StreamInput(preferences)
|
val input = StreamInput(preferences)
|
||||||
val session = StreamSession(connectInfo, input)
|
val session = StreamSession(connectInfo, preferences.logVerbose, input)
|
||||||
|
|
||||||
private var _onScreenControlsEnabled = MutableLiveData<Boolean>(preferences.onScreenControlsEnabled)
|
private var _onScreenControlsEnabled = MutableLiveData<Boolean>(preferences.onScreenControlsEnabled)
|
||||||
val onScreenControlsEnabled: LiveData<Boolean> get() = _onScreenControlsEnabled
|
val onScreenControlsEnabled: LiveData<Boolean> get() = _onScreenControlsEnabled
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue