diff --git a/app/src/main/assets/config.static b/app/src/main/assets/config.static index 1a71cde..17bb0f1 100644 --- a/app/src/main/assets/config.static +++ b/app/src/main/assets/config.static @@ -18,7 +18,7 @@ video_source avformat,android_camera,1 videnc_format yuv420p audio_jitter_buffer_type adaptive audio_jitter_buffer_delay 0-20 -video_jitter_buffer_type adaptive +video_jitter_buffer_type off video_jitter_buffer_delay 1-100 rtp_stats yes rtp_timeout 60 diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index f249320..b14cf9b 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -116,7 +116,7 @@ add_library(lib_baresip STATIC IMPORTED) set_target_properties(lib_baresip PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/baresip/lib/${ANDROID_ABI}/libbaresip.a) -add_library(baresip SHARED baresip.c vidisp.c) +add_library(baresip SHARED baresip.c vidisp.c serial.c) #set(CMAKE_SHARED_LINKER_FLAGS # "${CMAKE_SHARED_LINKER_FLAGS} -u AImageReader_new") diff --git a/app/src/main/cpp/serial.c b/app/src/main/cpp/serial.c new file mode 100644 index 0000000..db3fba0 --- /dev/null +++ b/app/src/main/cpp/serial.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// +// Created by ritos on 2025-03-10. +// + +//------------------------------------------------------------------------------ +// 설명 : 시리얼포트를 연다. +// 주의 : RTS/CTS 를 제어하지 않는다. +// 시리얼포트를 열고 이전의 포트설정상태를 저장하지 않았다. +//------------------------------------------------------------------------------ +int open_serial(const char *dev_name, int baud, int vtime, int vmin ) +{ + int fd; + struct termios newtio; + // 시리얼포트를 연다. + fd = open( dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK ); + if ( fd < 0 ) + { + // 화일 열기 실패 + printf( "Device OPEN FAIL %s\n", dev_name ); + return -1; + } + // 시리얼 포트 환경을 설정한다. + memset(&newtio, 0, sizeof(newtio)); + newtio.c_iflag = IGNPAR; // non-parity + newtio.c_oflag = 0; + newtio.c_cflag = CS8 | CLOCAL | CREAD; // NO-rts/cts + + switch( baud ) + { + case 115200 : newtio.c_cflag |= B115200; break; + case 57600 : newtio.c_cflag |= B57600; break; + case 38400 : newtio.c_cflag |= B38400; break; + case 19200 : newtio.c_cflag |= B19200; break; + case 9600 : newtio.c_cflag |= B9600; break; + case 4800 : newtio.c_cflag |= B4800; break; + case 2400 : newtio.c_cflag |= B2400; break; + default : newtio.c_cflag |= B115200; break; + } + //set input mode (non-canonical, no echo,.....) + newtio.c_lflag = 0; + newtio.c_cc[VTIME] = vtime; // timeout 0.1초 단위 + newtio.c_cc[VMIN] = vmin; // 최소 n 문자 받을 때까진 대기 + tcflush ( fd, TCIFLUSH ); + tcsetattr( fd, TCSANOW, &newtio ); + return fd; +} +//------------------------------------------------------------------------------ +// 설명 : 시리얼포트를 닫는다. +// 주의 : +//------------------------------------------------------------------------------ +void close_serial( int fd ) +{ + close( fd ); +} + +JNIEXPORT jint JNICALL Java_com_tutpro_baresip_plus_Utils_openSerial(JNIEnv *env, jobject thiz, jstring strDev, jint baudrate) +{ + (void)env; + (void)thiz; + const char *pType; + int result; + + pType = (*env)->GetStringUTFChars(env, strDev, NULL); + result = open_serial(pType, baudrate, 100, 1); + (*env)->ReleaseStringUTFChars(env, strDev, pType); + + return result; +} + +JNIEXPORT jint JNICALL Java_com_tutpro_baresip_plus_Utils_readSerial(JNIEnv *env, jobject thiz, jint devHandle, jbyteArray buffer, jint size) +{ + (void)env; + (void)thiz; + int result; + + jbyte *pBuffer = (*env)->GetByteArrayElements(env, buffer, NULL); + result = read( devHandle, (char *)pBuffer, size ); + (*env)->ReleaseByteArrayElements(env, buffer, pBuffer, 0); + + return result; +} + +JNIEXPORT jint JNICALL Java_com_tutpro_baresip_plus_Utils_writeSerial(JNIEnv *env, jobject thiz, jint devHandle, jbyteArray buffer, jint size) +{ + (void)env; + (void)thiz; + int result; + + jbyte *pBuffer = (*env)->GetByteArrayElements(env, buffer, NULL); + result = write( devHandle, (char *)pBuffer, size ); + (*env)->ReleaseByteArrayElements(env, buffer, pBuffer, 0); + + return result; +} + +JNIEXPORT jint JNICALL Java_com_tutpro_baresip_plus_Utils_closeSerial(JNIEnv *env, jobject thiz, jint devHandle) +{ + (void)env; + (void)thiz; + close_serial(devHandle); + + return 1; +} diff --git a/app/src/main/cpp/vidisp.c b/app/src/main/cpp/vidisp.c index db51b59..4807134 100644 --- a/app/src/main/cpp/vidisp.c +++ b/app/src/main/cpp/vidisp.c @@ -73,6 +73,27 @@ static void renderer_destroy(struct vidisp_st *st) gst = NULL; } +static void renderer_destroy_self(struct vidisp_st *st) +{ + LOGD("At renderer_destroy_self() on thread %li\n", (long)pthread_self()); + + if (st->display != EGL_NO_DISPLAY) { + eglMakeCurrent(st->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (st->surface != EGL_NO_SURFACE) { + eglDestroySurface(st->display, st->surface); + st->surface = EGL_NO_SURFACE; + } + if (st->context != EGL_NO_CONTEXT) { + eglDestroyContext(st->display, st->context); + st->context = EGL_NO_CONTEXT; + } + eglTerminate(st->display); + st->display = EGL_NO_DISPLAY; + } + eglReleaseThread(); + gst_self = NULL; +} + static void destructor(void *arg) { struct vidisp_st *st = arg; @@ -81,6 +102,14 @@ static void destructor(void *arg) mem_deref(st->vf); } +static void destructor_self(void *arg) +{ + struct vidisp_st *st = arg; + + renderer_destroy_self(st); + mem_deref(st->vf); +} + static int context_initialize(struct vidisp_st *st) { const EGLint attribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, @@ -166,6 +195,93 @@ static int context_initialize(struct vidisp_st *st) return 0; } + +static int context_initialize_self(struct vidisp_st *st) +{ + const EGLint attribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, EGL_NONE}; + + EGLDisplay display; + EGLConfig config; + EGLint numConfigs; + EGLint format; + EGLSurface surface; + EGLContext context; + + if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) { + LOGW("eglGetDisplay() returned error %d\n", eglGetError()); + return eglGetError(); + } + if (!eglInitialize(display, NULL, NULL)) { + LOGW("eglInitialize() returned error %d\n", eglGetError()); + return eglGetError(); + } + + if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) { + LOGW("eglChooseConfig() returned error %d\n", eglGetError()); + renderer_destroy_self(st); + return eglGetError(); + } + + if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) { + LOGW("eglGetConfigAttrib() returned error %d\n", eglGetError()); + renderer_destroy_self(st); + return eglGetError(); + } + + ANativeWindow_setBuffersGeometry(st->window, 0, 0, format); + + if (!(surface = eglCreateWindowSurface(display, config, st->window, NULL))) { + LOGW("eglCreateWindowSurface() returned error %s\n", egl_error(eglGetError())); + renderer_destroy_self(st); + return eglGetError(); + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + LOGW("eglBindApi failed with error %s\n", egl_error(eglGetError())); + renderer_destroy_self(st); + return eglGetError(); + } + + if (!(context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL))) { + LOGW("eglCreateContext() returned error %d\n", eglGetError()); + renderer_destroy_self(st); + return eglGetError(); + } + + if (!eglMakeCurrent(display, surface, surface, context)) { + LOGW("eglMakeCurrent() returned error %d\n", eglGetError()); + renderer_destroy_self(st); + return eglGetError(); + } + + if (!eglQuerySurface(display, surface, EGL_WIDTH, &st->width) + || !eglQuerySurface(display, surface, EGL_HEIGHT, &st->height)) { + LOGW("eglQuerySurface() returned error %d\n", eglGetError()); + renderer_destroy_self(st); + return eglGetError(); + } + + LOGD("RenderSelf buffer w/h = %d/%d", st->width, st->height); + + st->display = display; + st->surface = surface; + st->context = context; + + glDisable(GL_DITHER); + glEnable(GL_DEPTH_TEST); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + resize = false; + resize_self = false; + + LOGD("Rendered contextSelf initialized"); + + return 0; +} + + int opengles_alloc(struct vidisp_st **stp, const struct vidisp *vd, struct vidisp_prm *prm, const char *dev, vidisp_resize_h *resizeh, void *arg) { @@ -217,9 +333,9 @@ int opengles_alloc_self(struct vidisp_st **stp, const struct vidisp *vd, struct LOGD("At opengles_alloc_self() on thread %li\n", (long)pthread_self()); if (gst_self) - renderer_destroy(gst_self); + renderer_destroy_self(gst_self); - gst_self = mem_zalloc(sizeof(*gst_self), destructor); + gst_self = mem_zalloc(sizeof(*gst_self), destructor_self); if (!gst_self) return ENOMEM; @@ -612,11 +728,11 @@ static int opengles_render_self(struct vidisp_st *st) err = texture_init(st); if (err) { - LOGW("opengles_render_self: failed to initialize texture\n"); + LOGW("[SELF] opengles_render_self: failed to initialize texture\n"); return err; } - LOGD("video frame width/height = %d/%d\n", st->vf->size.w, st->vf->size.h); + LOGD("[SELF] video frame width/height = %d/%d\n", st->vf->size.w, st->vf->size.h); #if 1 // 원본 이미지 원본 크기를 View 에 매핑. 작으면 가운데로, 크면 Crop 발생 frame_width_self = st->vf->size.w; @@ -729,22 +845,22 @@ int opengles_display_self( /* This is hack to make sure that context is initialised on the same thread */ if (!st->context) { - err = context_initialize(st); + err = context_initialize_self(st); if (err) { - LOGW("Renderer context init failed with error %d\n", err); + LOGW("[SELF] Renderer context init failed with error %d\n", err); return err; } } if (!st->vf) { if (frame->size.w & 3) { - LOGW("opengles_display: frame width must be multiple of 4\n"); + LOGW("[SELF] opengles_display: frame width must be multiple of 4\n"); return EINVAL; } err = vidframe_alloc(&st->vf, VID_FMT_RGB565, &frame->size); if (err) { - LOGW("opengles_display: vidframe_alloc failed: %d\n", err); + LOGW("[SELF] opengles_display: vidframe_alloc failed: %d\n", err); return err; } } @@ -754,8 +870,16 @@ int opengles_display_self( opengles_render_self(st); err = eglSwapBuffers(st->display, st->surface); - if (!err) - LOGW("eglSwapBuffers() returned error %s\n", egl_error(eglGetError())); + if (!err) { + LOGW("[SELF] eglSwapBuffers() returned error %s\n", egl_error(eglGetError())); + renderer_destroy_self(st); + mem_deref(st->vf); + + err = context_initialize_self(st); + err = vidframe_alloc(&st->vf, VID_FMT_RGB565, &frame->size); + glDeleteTextures(1, &st->texture_id); + st->texture_id = 0; + } return err; } @@ -808,20 +932,20 @@ JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_VideoView_set_1surfaceSelf( { int w, h; - LOGD("At set_surface() on thread %li\n", (long)pthread_self()); + LOGD("[SELF] At set_surface() on thread %li\n", (long)pthread_self()); if (surface != 0) { window_self = ANativeWindow_fromSurface(env, surface); w = ANativeWindow_getWidth(window_self); h = ANativeWindow_getHeight(window_self); if ((w != window_width_self) || (h != window_height_self)) { - LOGI("Got new windowSelf %p with w/h = %d/%d", window_self, w, h); + LOGI("[SELF] Got new windowSelf %p with w/h = %d/%d", window_self, w, h); window_width_self = w; window_height_self = h; resize_self = true; } } else { - LOGI("Releasing windowSelf"); + LOGI("[SELF] Releasing windowSelf"); ANativeWindow_release(window_self); } } diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt index 1d660ad..4cdb38a 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt @@ -216,10 +216,10 @@ object Config { val videoSize = previousVariable("video_size") BaresipService.videoSize = if (videoSize !in videoSizes) { - if ("1280x720" in videoSizes) - Size(1280, 720) + if ("1920x1080" in videoSizes) + Size(1920, 1080) else - Size(640, 480) + Size(1280, 720) } else { Size(videoSize.substringBefore("x").toInt(), videoSize.substringAfter("x").toInt()) diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt index 72a089f..9e534ee 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt @@ -13,12 +13,12 @@ import android.content.Intent.ACTION_DIAL import android.content.Intent.ACTION_VIEW import android.content.pm.PackageManager import android.content.res.Configuration -import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.hardware.display.DisplayManager import android.media.AudioManager import android.media.MediaActionSound import android.net.Uri import android.os.* +import android.os.StrictMode.VmPolicy import android.provider.DocumentsContract import android.provider.MediaStore import android.text.InputType @@ -46,7 +46,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.tutpro.baresip.plus.Utils.showSnackBar import com.tutpro.baresip.plus.databinding.ActivityMainBinding -import org.w3c.dom.Text import java.io.File import java.text.SimpleDateFormat import java.time.LocalDateTime @@ -54,6 +53,7 @@ import java.time.format.DateTimeFormatter import java.util.* import kotlin.system.exitProcess + class SecondScreenPresentation(context: Context, display: Display) : Presentation(context, display) { override fun onCreate(savedInstanceState: Bundle?) { @@ -159,6 +159,18 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) +// if (BuildConfig.DEBUG) { +// +// } +// +// StrictMode.setVmPolicy( +// VmPolicy.Builder() +// .detectLeakedClosableObjects() // ✨ close() 호출 누락 감지 +// .penaltyLog() // Logcat에 로그 출력 +// .penaltyDeath() // 앱 크래시 (원인 추적 용이) +// .build() +// ) + enableEdgeToEdge() AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) @@ -2671,6 +2683,7 @@ class MainActivity : AppCompatActivity() { if (atStartup) moveTaskToBack(true) } + } private fun backup(password: String) { diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt index 32b2270..64f6716 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt @@ -608,6 +608,7 @@ object Utils { RandomAccessFile(filePath, "rw").use { raf -> raf.fd.sync() // eMMC에 확실히 기록 + raf.close() } } catch (e: IOException) { @@ -1185,6 +1186,9 @@ object Utils { } output.fd.sync() + output.close() + + input.close() } } @@ -1351,5 +1355,9 @@ object Utils { ).joinToString(".") } + external fun openSerial(strDev: String, baudrate: Int): Int // by ritoseo + external fun readSerial(devHandle:Int, buffer: ByteArray, size: Int): Int // by ritoseo + external fun writeSerial(devHandle:Int, buffer: ByteArray, size: Int): Int // by ritoseo + external fun closeSerial(devHandle: Int): Int // by ritoseo } diff --git a/distribution.video/baresip/lib/arm64-v8a/libbaresip.a b/distribution.video/baresip/lib/arm64-v8a/libbaresip.a index b043d60..d44bf75 100644 Binary files a/distribution.video/baresip/lib/arm64-v8a/libbaresip.a and b/distribution.video/baresip/lib/arm64-v8a/libbaresip.a differ diff --git a/distribution.video/ffmpeg/lib/arm64-v8a/libavdevice.so b/distribution.video/ffmpeg/lib/arm64-v8a/libavdevice.so index b064943..03cc0f1 100644 Binary files a/distribution.video/ffmpeg/lib/arm64-v8a/libavdevice.so and b/distribution.video/ffmpeg/lib/arm64-v8a/libavdevice.so differ