#pragma once #include "cvmmap_streamer/config/runtime_config.hpp" #include #include #include #include #include #include #include namespace cvmmap_streamer::protocol { struct RtmpPublisherStats { std::uint64_t access_units{0}; std::uint64_t access_unit_bytes{0}; std::uint64_t video_messages{0}; std::uint64_t bytes_sent{0}; std::uint64_t send_errors{0}; std::uint64_t publish_failures{0}; std::uint64_t reconnect_attempts{0}; std::uint64_t reconnect_successes{0}; std::uint64_t reconnect_failures{0}; }; class RtmpPublisher { public: RtmpPublisher() = default; ~RtmpPublisher(); RtmpPublisher(const RtmpPublisher &) = delete; RtmpPublisher &operator=(const RtmpPublisher &) = delete; RtmpPublisher(RtmpPublisher &&other) noexcept; RtmpPublisher &operator=(RtmpPublisher &&other) noexcept; [[nodiscard]] static std::expected create(const RuntimeConfig &config); [[nodiscard]] std::expected publish_access_unit(std::span access_unit, std::uint64_t pts_ns); [[nodiscard]] const RtmpPublisherStats &stats() const; void on_stream_reset(); void log_metrics() const; private: struct Session { std::string original_url{}; std::string host{}; std::uint16_t port{1935}; std::string app{}; std::string stream{}; std::string tc_url{}; int socket_fd{-1}; std::uint32_t out_chunk_size{128}; std::uint32_t stream_id{1}; bool sequence_header_sent{false}; std::uint32_t reconnect_backoff_ms{250}; std::uint32_t consecutive_reconnect_failures{0}; std::chrono::steady_clock::time_point reconnect_due_at{}; bool in_cooldown{false}; }; [[nodiscard]] std::expected connect_session(Session &session); void schedule_reconnect(Session &session, std::string_view reason, bool startup_path); void close_session(Session &session); CodecType codec_{CodecType::H264}; RtmpMode mode_{RtmpMode::Enhanced}; std::vector sessions_{}; RtmpPublisherStats stats_{}; bool had_successful_video_message_{false}; bool warned_all_sessions_closed_{false}; }; }