/* Desktop publisher: GUI управляет источниками и AudioDevice, workers кодируют видео/Opus. * Окно не владеет трансляцией. Stop закрывает callbacks; GUI ждёт workers асинхронно, затем отправляет FIN. * Captured video/preview хранят только последний кадр; публикация использует общий C actor. */ #pragma once #include #include #include #include #include #include #include #include #include "live_video_encoder.h" #include "stream_video_modes.h" #include "audio_capture.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; QSize size; QList modes; QPointer screen; // Живой монитор; удаление устройства не должно переключать захват на его одноимённого соседа. bool sameSource(const StreamVideoSource& other) const { return kind == other.kind && id == other.id && window == other.window && screen == other.screen; } }; struct StreamPublishConfig { StreamVideoSource source; LiveVideoConfig video; QString microphone; bool audio = true; bool showCursor = true; bool nativeSize = false, automaticBitrate = false; }; 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; QVariant previewFrame() const; QList codecs() const; static QList sources(); static bool supported(); static bool cursorSupported(const StreamVideoSource& source); void setMuted(bool muted); bool muted() const; uint64_t softwareEncodingRequest() const; void answerSoftwareEncoding(uint64_t generation, bool allow); signals: void codecsChanged(); void sourcesChanged(); 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); void softwareEncodingRequested(uint64_t generation, const QString& codec, const QString& details); private: struct Impl; std::unique_ptr m; AudioCapture 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(); bool finishStop(); void imageLoop(); void videoLoop(StreamPublishConfig initial); void audioLoop(); void captureAudio(const AudioCapture::Frame& frame); };