diff --git a/tools/chatgui/src/call_video_engine.cpp b/tools/chatgui/src/call_video_engine.cpp index 6fda6866..6d4d58a6 100644 --- a/tools/chatgui/src/call_video_engine.cpp +++ b/tools/chatgui/src/call_video_engine.cpp @@ -53,7 +53,7 @@ struct CallVideoEngine::Impl { QByteArray cameraId; bool captureActive = false; uint64_t captured = 0; - std::atomic publicationEpoch{0}, pendingSerial{0}, ackSerial{0}; + std::atomic pendingSerial{0}, ackSerial{0}; std::atomic presentedAt{0}; bool presentationDriven = false; uint64_t publicationSerial = 0; @@ -136,7 +136,7 @@ CallVideoEngine::CallVideoEngine(QObject* parent) : QObject(parent), m(std::make } CallVideoEngine::~CallVideoEngine() { stop(); delete m->guiNotifier; } void CallVideoEngine::setPresentationDriven(bool enabled) { - std::lock_guard guard(m->lock); m->presentationDriven = enabled; + m->presentationDriven = enabled; } void CallVideoEngine::imagePresented(quint64 serial) { if (!serial || serial != m->pendingSerial.load(std::memory_order_acquire) || serial == m->ackSerial.load()) return; @@ -158,7 +158,10 @@ void CallVideoEngine::deliverImage() { QImage image; if (m->publicationVideo) { const auto* slot = m->pictures.readSlot(); - if (!slot) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video GUI missing published slot serial=%llu", (unsigned long long)serial); return; } + if (!slot) { + DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video GUI missing published slot serial=%llu; stopping video", (unsigned long long)serial); + stop(); return; + } image = slot->image; } const int64_t now = nowUs(), wait = now - queued; @@ -228,7 +231,7 @@ void CallVideoEngine::stop() { if (m->tx.joinable()) m->tx.join(); if (m->rx.joinable()) m->rx.join(); if (m->id) call_video_port_close(m->id); - ++m->publicationEpoch; m->pendingSerial = 0; m->paintWaitMax = 0; + m->pendingSerial = 0; m->paintWaitMax = 0; while (const auto* event = m->logEvents.readSlot()) { call_video_playout_log_event(event); m->logEvents.release(); } m->id = 0; m->enabled = false; emit imageChanged({}, 0); } diff --git a/tools/chatgui/src/call_video_engine.h b/tools/chatgui/src/call_video_engine.h index 481fde01..4ae50db8 100644 --- a/tools/chatgui/src/call_video_engine.h +++ b/tools/chatgui/src/call_video_engine.h @@ -14,8 +14,8 @@ public: void start(quint64 id); void stop(); void setVideo(bool enabled, const QByteArray& camera, int width, int height, int codec); - void setPresentationDriven(bool enabled); // Окно подтверждает рисование; без окна достаточно доставки signal. - void imagePresented(quint64 serial); + void setPresentationDriven(bool enabled); // GUI-поток: окно подтверждает рисование, иначе достаточно доставки signal. + void imagePresented(quint64 serial); // GUI-поток; повторный/старый ACK безопасно игнорируется. signals: void camerasChanged(const CallCameraDevices& devices); void imageChanged(const QImage& image, quint64 serial); diff --git a/tools/chatgui/src/call_video_queue.h b/tools/chatgui/src/call_video_queue.h index f71823ca..c01f44c6 100644 --- a/tools/chatgui/src/call_video_queue.h +++ b/tools/chatgui/src/call_video_queue.h @@ -10,18 +10,18 @@ template class CallVideoQueue { static_assert(Capacity > 0); static_assert(std::atomic::is_always_lock_free); - std::array slots{}; + std::array entries{}; alignas(64) std::atomic written{0}; alignas(64) std::atomic consumed{0}; public: T* writeSlot() { const uint64_t tail = written.load(std::memory_order_relaxed); - return tail - consumed.load(std::memory_order_acquire) < Capacity ? &slots[tail % Capacity] : nullptr; + return tail - consumed.load(std::memory_order_acquire) < Capacity ? &entries[tail % Capacity] : nullptr; } void publish() { written.fetch_add(1, std::memory_order_release); } const T* readSlot() const { const uint64_t head = consumed.load(std::memory_order_relaxed); - return head < written.load(std::memory_order_acquire) ? &slots[head % Capacity] : nullptr; + return head < written.load(std::memory_order_acquire) ? &entries[head % Capacity] : nullptr; } void release() { consumed.fetch_add(1, std::memory_order_release); } // Вызывается только producer/consumer: собственный индекс во время снимка не меняется. @@ -30,7 +30,7 @@ public: return static_cast(written.load(std::memory_order_acquire) - head); } void reset() { - for (auto& slot : slots) slot = {}; + for (auto& slot : entries) slot = {}; written.store(0, std::memory_order_relaxed); consumed.store(0, std::memory_order_relaxed); } };