// rtsp_manager.hpp ##pragma once #include #include #include #include #include #include #include #include #include #include #include "app_config.hpp" #include "mqtt_client_wrapper.hpp" class RTMPManager { public: enum class StreamResult { OK, PIPELINE_ERROR, CONNECTION_FAIL, EOS_RECEIVED, TIMEOUT, UNKNOWN }; struct StreamStatus { bool running; StreamResult last_result; std::string last_error; }; struct StreamResultInfo { int loc{-1}; std::string url; int result{1}; // 0 success, 1 fail std::string reason; }; using StreamCallback = std::function; static void init(); static StreamResultInfo start_camera(const Camera &cam, StreamType type); static StreamResultInfo stop_camera(const std::string &cam_name, StreamType type); static void stop_all(); static bool is_streaming(const std::string &cam_name, StreamType type); static bool is_any_streaming(); static std::string get_stream_url(const std::string &cam_name, StreamType type); static void set_status_callback(StreamCallback cb); // Internal helpers static void update_status(const std::string &key, const StreamStatus &status); private: struct StreamContext { std::atomic running{false}; std::thread thread; StreamStatus status; StreamContext() = default; StreamContext(const StreamContext &) = delete; StreamContext &operator=(const StreamContext &) = delete; }; static std::string make_stream_key(const std::string &cam_name, StreamType type); static GstElement *create_pipeline(const Camera &cam, StreamType type); static void stream_loop(Camera cam, StreamType type); static std::unordered_map> streams; static std::mutex streams_mutex; static StreamCallback status_callback; };