From 470001bbab08b2e4fa465011afacaa9906fcfce1 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 14 Oct 2026 12:56:26 +0200 Subject: [PATCH] End desktop publication on fatal audio worker failure --- tools/chatgui/src/stream_publish_engine.cpp | 20 +++++++++++++++----- tools/chatgui/src/stream_publish_engine.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/chatgui/src/stream_publish_engine.cpp b/tools/chatgui/src/stream_publish_engine.cpp index 8445689e..08a1d31c 100644 --- a/tools/chatgui/src/stream_publish_engine.cpp +++ b/tools/chatgui/src/stream_publish_engine.cpp @@ -250,7 +250,7 @@ bool StreamPublishEngine::start(uint64_t group, const StreamPublishConfig& confi try { m->videoThread = std::thread(&StreamPublishEngine::videoLoop, this); if (config.audio) m->audioThread = std::thread(&StreamPublishEngine::audioLoop, this); - } catch (const std::system_error& error) { sourceFailed(m->generation, QString::fromUtf8(error.what())); return false; } + } catch (const std::system_error& error) { publicationFailed(m->id, QString::fromUtf8(error.what())); return false; } if (!openSource(config) || (config.audio && !openMicrophone())) { sourceFailed(m->generation, text("Could not open the selected capture device")); return false; } @@ -288,6 +288,13 @@ void StreamPublishEngine::sourceFailed(uint64_t generation, const QString& error if (rollback) reconfigure(restore); else stop(); } +/* Ошибку общего audio worker нельзя исправить заменой только video encoder. */ +void StreamPublishEngine::publicationFailed(uint64_t id, const QString& error) { + if (id != m->id || !m->running) return; + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop publication failed id=%llu reason=%s", (unsigned long long)id, qPrintable(error)); + emit errorOccurred(error); stop(); +} + /* Сначала callbacks, затем workers; FIN не обгоняет уже принятые access units. */ void StreamPublishEngine::stop() { if (!m->running.exchange(false)) return; @@ -303,9 +310,11 @@ bool StreamPublishEngine::openMicrophone() { m_capture.close(); m->audioAnchor = -1; m->audioFrames = 0; auto config = this->config(); auto* context = SoundManager::instance()->context(); - if (!context) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop stream audio context unavailable"); return false; } + if (!context) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop stream audio context unavailable"); m_capture.retryLater(); return false; } ma_device_id device; bool selected = SoundManager::deviceId(config.microphone, &device); - if (!config.microphone.isEmpty() && !selected) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop selected microphone ID is unavailable"); return false; } + if (!config.microphone.isEmpty() && !selected) { + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop selected microphone ID is unavailable"); m_capture.retryLater(); return false; + } for (int channels : {2, 1}) { ma_device_config capture = ma_device_config_init(ma_device_type_capture); capture.capture.format = ma_format_s16; capture.capture.channels = channels; capture.sampleRate = 48000; @@ -347,12 +356,13 @@ void StreamPublishEngine::captureAudio(const void* input, unsigned frames) { } void StreamPublishEngine::audioLoop() { + const uint64_t id = m->id; auto* encoder = opus_codec_encoder_create(48000, 2); auto* compressor = audio_compressor_create(); int result = encoder && compressor ? opus_codec_encoder_application_set(encoder, OPUS_CODEC_APP_AUDIO) : -1; if (result >= 0) result = opus_codec_encoder_bitrate_set(encoder, 128000); if (result < 0) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop stream audio encoder initialization failed"); - QMetaObject::invokeMethod(this, [this] { sourceFailed(m->generation, text("Audio encoder initialization failed")); }); + QMetaObject::invokeMethod(this, [this, id] { publicationFailed(id, text("Audio encoder initialization failed")); }); } else { int16_t pcm[1920]{}; unsigned used = 0; uint64_t sequence = 0; int64_t pts = 0, expected = -1, lastSent = -1; int settings[3] = {-1, -1, -1}; @@ -396,7 +406,7 @@ void StreamPublishEngine::audioLoop() { used = 0; } if (result < 0) { - QMetaObject::invokeMethod(this, [this] { sourceFailed(m->generation, text("Audio encoding failed")); }); break; + QMetaObject::invokeMethod(this, [this, id] { publicationFailed(id, text("Audio encoding failed")); }); break; } } } diff --git a/tools/chatgui/src/stream_publish_engine.h b/tools/chatgui/src/stream_publish_engine.h index 3065bcc6..5f879613 100644 --- a/tools/chatgui/src/stream_publish_engine.h +++ b/tools/chatgui/src/stream_publish_engine.h @@ -61,6 +61,7 @@ private: void closeSource(); bool openMicrophone(); void sourceFailed(uint64_t generation, const QString& error); + void publicationFailed(uint64_t id, const QString& error); void tick(); void videoLoop(); void audioLoop();