diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index 94298521..e9f35119 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -1479,7 +1479,7 @@ void MessageList::onRadioTalk(quint64 groupId, quint64 srcNodeId, bool on) { /* Каталог выбранного канала не удерживает media owner; DM/пустой target снимает наблюдение. */ void MessageList::watchStreams() { - if (gui_stream_ready()) gui_stream_watch(isDmChannel(m_currentChannelId) ? 0 : m_currentChannelId.toULongLong()); + gui_stream_watch(isDmChannel(m_currentChannelId) ? 0 : m_currentChannelId.toULongLong()); } void MessageList::clearStreams() { m_streamSources.clear(); m_streamBtn->hide(); } diff --git a/tools/chatgui/tests/test_stream_view.cpp b/tools/chatgui/tests/test_stream_view.cpp index 6ee621ce..aa352216 100644 --- a/tools/chatgui/tests/test_stream_view.cpp +++ b/tools/chatgui/tests/test_stream_view.cpp @@ -98,7 +98,8 @@ private slots: QCOMPARE(sqlite3_step(statement), SQLITE_ROW); group = QString::fromUtf8(reinterpret_cast(sqlite3_column_text(statement, 0))).toULongLong(); sqlite3_finalize(statement); QVERIFY(group); - chat_event_set_handler(inst, sourceEvent); QVERIFY(gui_stream_attach(inst)); uasync_mark_running(ua); + chat_event_set_handler(inst, sourceEvent); QVERIFY(gui_stream_watch(group)); + QVERIFY(gui_stream_attach(inst)); uasync_mark_running(ua); connect(&poll, &QTimer::timeout, this, [this] { uasync_poll(ua, 0); }); poll.start(1); } diff --git a/tools/chatgui/transport/stream_bridge.cpp b/tools/chatgui/transport/stream_bridge.cpp index f79205fe..6998b4df 100644 --- a/tools/chatgui/transport/stream_bridge.cpp +++ b/tools/chatgui/transport/stream_bridge.cpp @@ -31,7 +31,7 @@ void process(void*); /* Вызывается под lock; резервирование делает отказ команды наблюдаемым до изменения состояния. */ bool schedule() { - if (!bridge.inst || !uasync_is_running(bridge.inst->ua)) { + if (!bridge.inst) { DEBUG_WARN(DEBUG_CATEGORY_STREAM, "desktop stream command rejected: core unavailable"); return false; } if (bridge.pending) return true; @@ -150,6 +150,11 @@ bool gui_stream_attach(UTUN_INSTANCE* inst) { } bridge.inst = inst; bridge.output.clear(); bridge.bytes = 0; stream_set_event_callback(inst, mediaEvent, nullptr); + if (bridge.watchPending) { + bridge.watchPending = false; + if (stream_watch_sources(inst, bridge.watch) != STREAM_OK) + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop initial source watch failed group=%llx", (unsigned long long)bridge.watch); + } DEBUG_INFO(DEBUG_CATEGORY_STREAM, "desktop stream bridge attached"); return true; } @@ -167,6 +172,10 @@ void gui_stream_detach(UTUN_INSTANCE* inst) { bool gui_stream_watch(uint64_t group) { std::lock_guard guard(bridge.lock); + if (!bridge.inst) { + bridge.watch = group; bridge.watchPending = true; + DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop source watch queued until attach group=%llx", (unsigned long long)group); return true; + } if (!schedule()) return false; bridge.watch = group; bridge.watchPending = true; return true; }