Close failed stream capture without blocking the GUI

This commit is contained in:
evgeny committed 2026-10-16 16:03:14 +02:00
1 parent 86da11b2e1
commit 3ba7601ba4
2 files changed
+37 -3

No files matched your search

+30 -3
View File
@@ -98,6 +98,7 @@ AudioCapture::~AudioCapture() { close(); }
bool AudioCapture::open(const QString& input, Role role, int channels, uint64_t tag, Ready ready,
std::function<void()> stopped, Callback callback) {
if (closing()) { DEBUG_WARN(DEBUG_CATEGORY_CALL, "capture: previous device is still closing"); return false; }
close();
static std::vector<std::weak_ptr<Session>> sessions; // Только GUI; владение у подписчиков.
QString key = input;
@@ -129,13 +130,39 @@ bool AudioCapture::open(const QString& input, Role role, int channels, uint64_t
return running();
}
void AudioCapture::close() {
if (!m_session) return;
std::shared_ptr<AudioCapture::Session> AudioCapture::detach() {
if (!m_session) return {};
auto& slot = m_session->consumers[m_role == Role::Stream ? 0 : 1];
m_session->detach(slot); slot.client = nullptr;
DEBUG_INFO(DEBUG_CATEGORY_CALL, "capture: detached role=%s remaining=%d", m_role == Role::Stream ? "stream" : "radio",
int(m_session->consumers[0].client != nullptr) + int(m_session->consumers[1].client != nullptr));
m_session.reset(); m_callback = {}; m_ready = {}; m_stopped = {};
m_callback = {}; m_ready = {}; m_stopped = {};
return std::move(m_session);
}
void AudioCapture::close() {
if (m_closeThread.joinable()) m_closeThread.join();
detach().reset();
}
/* Callback отсоединён в GUI; session и контекст должны жить до завершения ma_device_uninit. */
void AudioCapture::closeAsync() {
if (closing()) return;
if (m_closeThread.joinable()) m_closeThread.join();
auto session = detach();
if (!session) return;
m_closeDone.store(false, std::memory_order_release);
DEBUG_INFO(DEBUG_CATEGORY_CALL, "capture: asynchronous close started shared=%d", session.use_count() > 1);
try {
m_closeThread = std::thread([this, session = std::move(session)]() mutable {
session.reset();
DEBUG_INFO(DEBUG_CATEGORY_CALL, "capture: asynchronous close completed");
m_closeDone.store(true, std::memory_order_release);
});
} catch (const std::system_error& error) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "capture: close worker failed: %s", error.what());
m_closeDone.store(true, std::memory_order_release);
}
}
void AudioCapture::recover() { if (m_session) m_session->recover(); }