Browse Source

Clean desktop stream lifecycle and event bridge logging

stream-multiview
evgeny 6 days ago
parent
commit
044a20d4a0
  1. 24
      tools/chatgui/src/stream_publish_engine.cpp
  2. 10
      tools/chatgui/src/streamplayer_window.cpp
  3. 5
      tools/chatgui/transport/gui_bridge_impl.cpp

24
tools/chatgui/src/stream_publish_engine.cpp

@ -176,10 +176,10 @@ StreamPublishEngine::StreamPublishEngine(QObject* parent) : QObject(parent), m(s
});
#ifdef HAVE_STREAM_CAPTURE
m->imageThread.reset(QThread::create([this] {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image worker started tid=%llu", (unsigned long long)(quintptr)QThread::currentThreadId());
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop image worker started tid=%llu", (unsigned long long)(quintptr)QThread::currentThreadId());
imageLoop();
m->imageProgress("release-thread-resources");
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image loop returned; releasing thread resources frames=%llu tid=%llu",
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop image loop returned; releasing thread resources frames=%llu tid=%llu",
(unsigned long long)m->imageFrames.load(), (unsigned long long)(quintptr)QThread::currentThreadId());
}));
m->imageThread->start();
@ -189,7 +189,7 @@ StreamPublishEngine::StreamPublishEngine(QObject* parent) : QObject(parent), m(s
}
StreamPublishEngine::~StreamPublishEngine() {
const int64_t destroyAt = monotonicUs();
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction begin id=%llu running=%d stopping=%d image_stage=%s image_frames=%llu",
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop publisher destruction begin id=%llu running=%d stopping=%d image_stage=%s image_frames=%llu",
(unsigned long long)m->id, m->running.load(), m->stopping, m->imageStage.load(), (unsigned long long)m->imageFrames.load());
m->destroying = true; blockSignals(true);
stop(); m_timer.stop(); m_previewTimer.stop();
@ -204,17 +204,13 @@ StreamPublishEngine::~StreamPublishEngine() {
m->stopping, m->imageJoined.load(), m->imageStage.load());
QEventLoop loop; QTimer timer;
int64_t reportAt = destroyAt;
bool firstPoll = true;
connect(&timer, &QTimer::timeout, &loop, [this, &loop, destroyAt, &reportAt, &firstPoll] {
if (firstPoll) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction GUI timer active"); firstPoll = false;
}
connect(&timer, &QTimer::timeout, &loop, [this, &loop, destroyAt, &reportAt] {
const bool imageDone = finishImageStop();
if (finishStop() && imageDone) { loop.quit(); return; }
const int64_t now = monotonicUs();
if (now - reportAt < 5000000) return;
reportAt = now;
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction waiting elapsed_ms=%lld stopping=%d workers_joined=%d "
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "desktop publisher destruction waiting elapsed_ms=%lld stopping=%d workers_joined=%d "
"video_stage=%s image_joined=%d image_stage=%s image_stage_age_ms=%lld image_frames=%llu microphone_closing=%d",
(long long)((now - destroyAt) / 1000), m->stopping, m->workersJoined.load(), m->videoStage.load(),
m->imageJoined.load(), m->imageStage.load(), (long long)((now - m->imageStageAt.load()) / 1000),
@ -222,12 +218,12 @@ StreamPublishEngine::~StreamPublishEngine() {
});
timer.start(10);
const int result = loop.exec(QEventLoop::ExcludeUserInputEvents);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction GUI loop exited result=%d stopping=%d image_joined=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop publisher destruction GUI loop exited result=%d stopping=%d image_joined=%d",
result, m->stopping, m->imageJoined.load());
if (m->stopping || !m->imageJoined)
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction GUI loop exited before worker cleanup completed");
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop publisher destruction GUI loop exited before worker cleanup completed");
}
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction complete elapsed_ms=%lld", (long long)((monotonicUs() - destroyAt) / 1000));
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop publisher destruction complete elapsed_ms=%lld", (long long)((monotonicUs() - destroyAt) / 1000));
}
bool StreamPublishEngine::supported() {
#ifdef HAVE_STREAM_CAPTURE
@ -721,13 +717,13 @@ bool StreamPublishEngine::finishStop() {
bool StreamPublishEngine::finishImageStop() {
if (m->imageJoined) return true;
if (!m->imageThread) {
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "desktop image worker missing before native thread completion");
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop image worker missing before native thread completion");
return false;
}
if (!m->imageThread->wait(0)) return false;
m->imageThread.reset();
m->imageJoined = true;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image native thread cleanup completed frames=%llu",
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "desktop image native thread cleanup completed frames=%llu",
(unsigned long long)m->imageFrames.load());
return true;
}

10
tools/chatgui/src/streamplayer_window.cpp

@ -305,7 +305,7 @@ void StreamPlayerWindow::decode() {
{ std::lock_guard<std::mutex> guard(p.lock); resync = p.resync; p.workerAt = nowUs(); gap = p.audioGap; }
/* Callback сохраняет снимок; печать выполняется worker без блокировки аудиоустройства. */
if (gap.count != reportedGaps && nowUs() - gapReportAt >= 1000000) {
DEBUG_WARN(DEBUG_CATEGORY_DEBUG,
DEBUG_WARN(DEBUG_CATEGORY_STREAM,
"desktop audio gap id=%llu count=%llu delta=%llu silence_frames=%llu cause=%s got=%u/%u "
"reserve_us=%lld feed_age_us=%lld worker_age_us=%lld audio_pts=%lld videoQ=%zu",
(unsigned long long)p.id, (unsigned long long)gap.count, (unsigned long long)(gap.count - reportedGaps),
@ -388,15 +388,11 @@ void StreamPlayerWindow::decode() {
observe();
if (record.pts > INT64_MAX) { fail(text("Invalid stream timestamp")); break; }
if (record.kind == StreamRecordKind::Audio) {
int result = 0, wanted = 0, stillWanted = 0;
int result = 0;
{ std::lock_guard<std::mutex> guard(p.lock);
if (p.sound) wanted = stream_playback_audio_needs_input(p.sound);
if (p.sound) result = stream_playback_audio_feed(p.sound, (int64_t)record.pts,
reinterpret_cast<const uint8_t*>(record.data.constData()), (size_t)record.data.size());
if (p.sound && result == 0) { p.audioFedAt = nowUs(); p.audioFedPts = (int64_t)record.pts; }
if (p.sound) stillWanted = stream_playback_audio_needs_input(p.sound); }
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "desktop audio feed id=%llu pts=%llu result=%d needs_input=%d->%d",
(unsigned long long)p.id, (unsigned long long)record.pts, result, wanted, stillWanted);
if (p.sound && result == 0) { p.audioFedAt = nowUs(); p.audioFedPts = (int64_t)record.pts; } }
if (result == -2) reset(true);
else if (result < 0) { fail(text("Stream audio decoder failed")); break; }
continue;

5
tools/chatgui/transport/gui_bridge_impl.cpp

@ -137,14 +137,9 @@ void GuiBridgeReceiver::processPost(int eventType, QByteArray data) {
if (g_avatar_result_cb) g_avatar_result_cb(d, dlen);
break;
case CHAT_EVT_MEMBER_FILES_RESPONSE:
if (dlen >= 16 + MF_WIRE_HEADER) DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG,
"member_files: bridge response id=%llu cmd=%s bytes=%d callback=%d",
(unsigned long long)mf_get64(d + 21), mf_command_text(d[18]), dlen, g_member_files_response_cb != nullptr);
if (g_member_files_response_cb) g_member_files_response_cb(d, dlen);
break;
case CHAT_EVT_MEMBER_FILES_TRANSFER:
if (dlen == 51) DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "member_files: bridge progress id=%llu state=%u callback=%d",
(unsigned long long)mf_get64(d), d[50], g_member_files_transfer_cb != nullptr);
if (g_member_files_transfer_cb) g_member_files_transfer_cb(d, dlen);
break;
case CHAT_EVT_DM_INVITE_RESULT:

Loading…
Cancel
Save