/* Desktop publisher: GUI управляет источниками и AudioDevice, workers кодируют видео/Opus. * Окно не владеет трансляцией. Stop закрывает callbacks, joins workers и отправляет FIN. * Captured video/preview хранят только последний кадр; публикация использует общий C actor. */ #pragma once #include #include #include #include #include #include #include "live_video_encoder.h" #include "audio_device.h" #include "audio_capture_lease.h" #include "../../../src/stream/stream_publisher.h" struct StreamVideoSource { enum Kind { Camera, Screen, Window }; Kind kind = Camera; QString name; QByteArray id; QVariant window; }; struct StreamPublishConfig { StreamVideoSource source; LiveVideoConfig video; QString microphone; bool audio = true; }; class StreamPublishEngine : public QObject { Q_OBJECT public: explicit StreamPublishEngine(QObject* parent = nullptr); ~StreamPublishEngine() override; bool start(uint64_t group, const StreamPublishConfig& config); bool reconfigure(const StreamPublishConfig& config); void stop(); bool active() const; bool running() const; uint64_t group() const; StreamPublishConfig config() const; QList codecs() const; static QList sources(); static bool supported(); void setMuted(bool muted); signals: void codecsChanged(); void stateChanged(const QString& state); void configurationChanged(); void previewVideoChanged(const QVariant& frame); void telemetryChanged(const stream_publisher_status& status); void errorOccurred(const QString& error); void audioChannelsChanged(int channels); private: struct Impl; std::unique_ptr m; AudioDevice m_capture; AudioCaptureLease m_microphone{AudioCaptureLease::Mode::Exclusive}; QTimer m_timer; QTimer m_previewTimer; bool openSource(const StreamPublishConfig& config); 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(); void captureAudio(const void* pcm, unsigned frames); };