From 432f2dcf00b8479faba2691a462908020796ce58 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 16 Oct 2026 16:48:34 +0200 Subject: [PATCH] Stop radio transmission when microphone PCM stops arriving --- tools/chatgui/src/radio_audio_engine.cpp | 21 +++++++++++++++++---- tools/chatgui/src/radio_audio_engine.h | 2 ++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tools/chatgui/src/radio_audio_engine.cpp b/tools/chatgui/src/radio_audio_engine.cpp index dbc4bcf8..40e38430 100644 --- a/tools/chatgui/src/radio_audio_engine.cpp +++ b/tools/chatgui/src/radio_audio_engine.cpp @@ -48,7 +48,8 @@ RadioAudioEngine::RadioAudioEngine() { auto* manager = SoundManager::instance(); if (m_captureId != manager->captureDevice()) { m_captureId = manager->captureDevice(); - m_capture.close(); + m_capture.closeAsync(); m_captureError.clear(); + emit stateChanged(); } if (m_playbackId != manager->playbackDevice()) { m_playbackId = manager->playbackDevice(); @@ -198,7 +199,9 @@ void RadioAudioEngine::reconfigureCapture() { int RadioAudioEngine::start(quint64 groupId) { if (m_active && m_groupId == groupId) return 0; + if (m_capture.closing()) { DEBUG_WARN(DEBUG_CATEGORY_RADIO, "RadioAudio: previous microphone is still closing"); return -1; } stop(); + m_captureError.clear(); if (!m_microphone.acquire()) { DEBUG_WARN(DEBUG_CATEGORY_RADIO, "RadioAudio: microphone owned by another operation"); return -1; } @@ -241,6 +244,14 @@ void RadioAudioEngine::recoverDevices() { if (!m_active) return; auto* manager = SoundManager::instance(); if (!m_outputAttached && manager->context()) m_outputAttached = manager->attachVoice(&m_voice, m_playbackId); + if (m_captureError.isEmpty() && m_capture.captureTimedOut()) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "RadioAudio: microphone has no PCM for 1000ms group=%016llx; disabling capture", + (unsigned long long)m_groupId.load()); + m_captureError = QCoreApplication::translate("ChatGui", "The microphone is not delivering audio. Select another microphone or restart."); + m_buttonTalking = m_hotkeyTalking = false; updateTalking(); + m_capture.closeAsync(); updateState(); emit stateChanged(); + } + if (!m_captureError.isEmpty() || m_capture.closing()) { updateState(); return; } if (m_capture.running() && !m_voice.captureRunning()) m_capture.close(); if (!m_capture.subscribed()) openCapture(); else m_capture.recover(); m_voice.setAecEnabled(chat_setting_get_int(gui_bridge_get_inst(), "aec_enabled", 1) != 0); @@ -279,7 +290,9 @@ void RadioAudioEngine::pauseDevices() { void RadioAudioEngine::stop() { m_recoveryTimer.stop(); - pauseDevices(); m_voice.stop(); + m_capture.closeAsync(); + SoundManager::instance()->detachVoice(&m_voice); m_outputAttached = false; + m_voice.stop(); m_microphone.release(); uint64_t group = m_groupId.exchange(0); bool talking = m_talking.exchange(false); @@ -293,7 +306,7 @@ void RadioAudioEngine::stop() { } void RadioAudioEngine::talkBegin() { - if (!m_active) return; + if (!m_active || !m_captureError.isEmpty()) return; m_buttonTalking = true; updateTalking(); } @@ -304,7 +317,7 @@ void RadioAudioEngine::talkEnd() { } void RadioAudioEngine::setHotkeyTalking(bool pressed) { - m_hotkeyTalking = pressed && m_active; + m_hotkeyTalking = pressed && m_active && m_captureError.isEmpty(); updateTalking(); } diff --git a/tools/chatgui/src/radio_audio_engine.h b/tools/chatgui/src/radio_audio_engine.h index 539d18c0..3654de52 100644 --- a/tools/chatgui/src/radio_audio_engine.h +++ b/tools/chatgui/src/radio_audio_engine.h @@ -54,6 +54,7 @@ public: bool captureAvailable() const { return m_captureAvailable; } bool isTransmitting() const { return m_transmitting; } QString settingsError() const { return m_settingsError; } + QString captureError() const { return m_captureError; } bool isTalking() const { return m_talking.load(); } bool isActive() const { return m_active.load(); } @@ -99,6 +100,7 @@ private: QTimer m_recoveryTimer; bool m_wantStereo = false; QString m_captureId, m_playbackId; + QString m_captureError; int m_captureChannels = 1; };