#pragma once #include #include #include #include #include #include #ifdef __linux__ #include #include #endif // Forward declarations for Pipewire/sdbus to avoid header pollution struct pw_thread_loop; struct pw_stream; struct pw_context; namespace sdbus { class IConnection; class IProxy; class Variant; } namespace scar { class VideoEncoder; // Forward declaration enum class ScreenCaptureBackend { FFMPEG_X11, // X11 via ffmpeg FFMPEG_WAYLAND, // Wayland via ffmpeg + portal FFMPEG_WINDOWS, // Windows GDI via ffmpeg PORTAL_PIPEWIRE // xdg-desktop-portal + Pipewire (Wayland/Hyprland) }; // Screen capture supporting multiple backends class ScreenCapture { public: ScreenCapture(); ~ScreenCapture(); // Auto-detect and start screen capture bool start(); // Start with specific backend bool start(ScreenCaptureBackend backend); // Stop capturing void stop(); // Check if currently capturing bool isCapturing() const { return capturing_; } // Set frame callback using FrameCallback = std::function& frameData, int width, int height)>; void setFrameCallback(FrameCallback callback); private: ScreenCaptureBackend detectBestBackend(); bool startX11Capture(); bool startWaylandCapture(); bool startWindowsCapture(); bool startPortalCapture(); // sdbus Portal methods bool initPortalConnection(); void cleanupPortalConnection(); std::string createPortalSession(); bool selectPortalSources(const std::string& session_handle); bool startPortalSession(const std::string& session_handle, uint32_t& node_id); int openPipeWireRemote(const std::string& session_handle); uint32_t getStreamsNodeId(const std::string& session_handle); // Portal async response handlers void onCreateSessionResponse(uint32_t response, const std::map& results); void onSelectSourcesResponse(uint32_t response, const std::map& results); void onStartSessionResponse(uint32_t response, const std::map& results); void setupResponseSignal(const std::string& request_handle, std::function&)> callback); // Pipewire methods bool initPipewire(int fd, uint32_t node_id); void cleanupPipewire(); static void onStreamProcess(void* userdata); static void onStreamParamChanged(void* userdata, uint32_t id, const struct spa_pod* param); bool capturing_; ScreenCaptureBackend backend_; FrameCallback frameCallback_; // sdbus members std::shared_ptr portal_connection_; std::unique_ptr screencast_proxy_; std::vector> request_proxies_; // Keep request proxies alive for signal handlers std::string session_path_; std::string pending_request_path_; bool portal_session_ready_; bool portal_sources_selected_; bool portal_started_; // Pipewire members pw_thread_loop* pw_loop_; pw_stream* pw_stream_; pw_context* pw_context_; spa_hook stream_listener_; int frame_width_; int frame_height_; uint32_t frame_format_; // SPA video format from PipeWire // Video encoder std::unique_ptr encoder_; }; } // namespace scar