diff --git a/tools/chatgui-android/libutun_lite/instance_lite.c b/tools/chatgui-android/libutun_lite/instance_lite.c index b12b0cc6..58204761 100644 --- a/tools/chatgui-android/libutun_lite/instance_lite.c +++ b/tools/chatgui-android/libutun_lite/instance_lite.c @@ -298,7 +298,7 @@ static void* instance_thread(void* arg) { IL_LOGI("instance created, node_id=0x%016llx", (unsigned long long)g_inst->node_id); /* Core owns SQLite and transport; this frontend starts only the chat service. */ - if (utun_core_start(g_inst) != 0 || chat_service_start(g_inst) != 0) { + if (utun_core_start(g_inst) != 0 || chat_service_start(g_inst) != 0 || android_stream_attach(g_inst) < 0) { IL_LOGE("core/chat start failed"); utun_instance_destroy(g_inst); g_inst = NULL; @@ -312,7 +312,6 @@ static void* instance_thread(void* arg) { return NULL; } - android_stream_attach(g_inst); /* sockets are now created — sync my addresses to DB */ chat_core_sync_my_addresses(g_inst); fire_local_sockets_event(); @@ -389,8 +388,9 @@ static void* instance_thread(void* arg) { chat_event_set_handler(g_inst, chat_event_forward); /* Recreate core and chat independently of UTUN. */ - if (utun_core_start(g_inst) != 0 || chat_service_start(g_inst) != 0) { IL_LOGE("poll exit: core/chat start failed"); break; } - android_stream_attach(g_inst); + if (utun_core_start(g_inst) != 0 || chat_service_start(g_inst) != 0 || android_stream_attach(g_inst) < 0) { + IL_LOGE("poll exit: core/chat/stream bridge start failed"); break; + } chat_core_sync_my_addresses(g_inst); fire_local_sockets_event(); if (g_inst->config->global.name[0]) chat_core_update_my_name(g_inst, g_inst->config->global.name); diff --git a/tools/chatgui-android/libutun_lite/stream_bridge.c b/tools/chatgui-android/libutun_lite/stream_bridge.c index b102d7c6..ea184aee 100644 --- a/tools/chatgui-android/libutun_lite/stream_bridge.c +++ b/tools/chatgui-android/libutun_lite/stream_bridge.c @@ -303,11 +303,16 @@ static void media_process(void *arg) { } /* Attach/detach — обязательная граница lifetime ядра. */ -void android_stream_attach(struct UTUN_INSTANCE *inst) { +int android_stream_attach(struct UTUN_INSTANCE *inst) { pthread_mutex_lock(&media_lock); + if (!inst || !inst->stream || (media_inst && media_inst != inst)) { + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "Android stream attach rejected inst=%p owner=%p", (void *)inst, (void *)media_inst); + pthread_mutex_unlock(&media_lock); return -1; + } media_inst = inst; stream_set_event_callback(inst, media_event, NULL); DEBUG_INFO(DEBUG_CATEGORY_STREAM, "Android stream bridge attached"); pthread_mutex_unlock(&media_lock); + return 0; } void android_stream_detach(struct UTUN_INSTANCE *inst) { pthread_mutex_lock(&media_lock); @@ -352,7 +357,11 @@ int android_stream_feed(uint64_t id, int video, uint64_t pts, int key, const uin } pthread_mutex_lock(&media_lock); int result = -1, track = video ? 0 : 1; - if (!media_inst || publisher.id != id || publisher.stopping || publisher.finished) goto done; + if (!media_inst || publisher.id != id || publisher.stopping || publisher.finished) { + DEBUG_WARN(DEBUG_CATEGORY_STREAM, "Android stream feed rejected id=%llu owner=%llu attached=%d stopping=%d finished=%d", + (unsigned long long)id, (unsigned long long)publisher.id, media_inst != NULL, publisher.stopping, publisher.finished); + goto done; + } if ((!video && !publisher.format.audio_codec) || (publisher.seen[track] && pts <= publisher.last_pts[track])) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "Android stream feed invalid track/PTS id=%llu pts=%llu", (unsigned long long)id, (unsigned long long)pts); goto done; diff --git a/tools/chatgui-android/libutun_lite/stream_bridge.h b/tools/chatgui-android/libutun_lite/stream_bridge.h index 646fa8c0..fbbcaa00 100644 --- a/tools/chatgui-android/libutun_lite/stream_bridge.h +++ b/tools/chatgui-android/libutun_lite/stream_bridge.h @@ -12,7 +12,8 @@ #include struct UTUN_INSTANCE; -void android_stream_attach(struct UTUN_INSTANCE *inst); +/* 0 attached, -1 invalid/busy: нельзя передать singleton другому ядру до detach старого. */ +int android_stream_attach(struct UTUN_INSTANCE *inst); void android_stream_detach(struct UTUN_INSTANCE *inst); int android_stream_open(uint64_t id, uint64_t group, uint64_t source, unsigned width, unsigned height, unsigned rotation, int audio);