Browse Source

Reserve broadcast capture exclusively while preserving shared voice I/O

master
evgeny 5 days ago
parent
commit
29313cce54
  1. 1
      src/stream/stream_publisher.c
  2. 30
      tools/chatgui/src/audio_capture_lease.h
  3. 2
      tools/chatgui/src/stream_publish_engine.h

1
src/stream/stream_publisher.c

@ -73,6 +73,7 @@ static void publisher_close(struct stream_publisher *p, int reason) {
p->handle = NULL; records_clear(&p->video); records_clear(&p->audio); p->handle = NULL; records_clear(&p->video); records_clear(&p->audio);
p->status.state = reason ? STREAM_PUBLISHER_FAILED : STREAM_PUBLISHER_ENDED; p->status.reason = reason; p->status.state = reason ? STREAM_PUBLISHER_FAILED : STREAM_PUBLISHER_ENDED; p->status.reason = reason;
p->status.video_bytes = p->status.audio_bytes = p->status.total_bytes = 0; p->status.video_bytes = p->status.audio_bytes = p->status.total_bytes = 0;
p->status.stream_bytes = p->status.transport_bytes = p->status.inflight_bytes = p->status.acked_1s = 0;
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "publisher closed id=%llu epoch=%llx reason=%d", DEBUG_INFO(DEBUG_CATEGORY_STREAM, "publisher closed id=%llu epoch=%llx reason=%d",
(unsigned long long)p->status.id, (unsigned long long)p->status.epoch, reason); (unsigned long long)p->status.id, (unsigned long long)p->status.epoch, reason);
} }

30
tools/chatgui/src/audio_capture_lease.h

@ -1,20 +1,34 @@
/* Единственный владелец desktop-микрофона: звонок, рация, запись либо трансляция. /* Desktop-микрофон: publisher получает Exclusive, существующие voice-контуры — Shared.
* Сохраняется совместная работа звонка/рации/записи; publisher исключает остальные captures в обе стороны.
* Lease берётся до открытия backend, сохраняется при recovery и освобождается после close/join. * Lease берётся до открытия backend, сохраняется при recovery и освобождается после close/join.
* Inline состояние общее для translation units; callback не обращается к lease. */ * Каждый lease использует управляющий поток, общее atomic состояние доступно из разных потоков. */
#pragma once #pragma once
#include <atomic> #include <atomic>
class AudioCaptureLease { class AudioCaptureLease {
public: public:
AudioCaptureLease() = default; enum class Mode { Shared, Exclusive };
explicit AudioCaptureLease(Mode mode = Mode::Shared) : m_mode(mode) {}
~AudioCaptureLease() { release(); } ~AudioCaptureLease() { release(); }
AudioCaptureLease(const AudioCaptureLease&) = delete; AudioCaptureLease(const AudioCaptureLease&) = delete;
AudioCaptureLease& operator=(const AudioCaptureLease&) = delete; AudioCaptureLease& operator=(const AudioCaptureLease&) = delete;
bool acquire() { bool acquire() {
const void* expected = nullptr; if (m_held) return true;
return owner.compare_exchange_strong(expected, this) || expected == this; int expected = 0;
if (m_mode == Mode::Exclusive) m_held = owners.compare_exchange_strong(expected, -1);
else {
expected = owners.load();
while (expected >= 0) if (owners.compare_exchange_weak(expected, expected + 1)) { m_held = true; break; }
}
return m_held;
} }
void release() { const void* expected = this; owner.compare_exchange_strong(expected, nullptr); } void release() {
bool held() const { return owner.load() == this; } if (!m_held) return;
if (m_mode == Mode::Exclusive) owners.store(0); else owners.fetch_sub(1);
m_held = false;
}
bool held() const { return m_held; }
private: private:
static inline std::atomic<const void*> owner{nullptr}; Mode m_mode;
bool m_held = false;
static inline std::atomic<int> owners{0};
}; };

2
tools/chatgui/src/stream_publish_engine.h

@ -54,7 +54,7 @@ private:
struct Impl; struct Impl;
std::unique_ptr<Impl> m; std::unique_ptr<Impl> m;
AudioDevice m_capture; AudioDevice m_capture;
AudioCaptureLease m_microphone; AudioCaptureLease m_microphone{AudioCaptureLease::Mode::Exclusive};
QTimer m_timer; QTimer m_timer;
bool openSource(const StreamPublishConfig& config); bool openSource(const StreamPublishConfig& config);
void closeSource(); void closeSource();

Loading…
Cancel
Save