#pragma once #include "IMediaController.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace rtc { class DataChannel; class PeerConnection; } namespace Slic3r { namespace GUI { class WebRtcMediaController : public IMediaController { public: struct Status { enum Kind { Connecting, Playing, Stopped, Failed } kind = Stopped; enum Code { ICE_FAILED, SIGNALING_CLOSED, UNAVAILABLE_BUSY, UNAVAILABLE_ERROR, UNAVAILABLE_DISABLED, DECODE_ERROR, TIMEOUT, } code = ICE_FAILED; // Identifies the Play attempt this status belongs to, so the // consumer can drop CallAfter-queued events from a superseded attempt. std::uint64_t epoch = 0; }; WebRtcMediaController(std::function frame_sink, std::function on_status); ~WebRtcMediaController() override; void set_signalling_channel(std::unique_ptr channel); std::uint64_t epoch() const { return m_epoch.load(); } bool is_active() const { return m_alive.load(); } void Load(wxURI) override {} void Play() override; void Stop() override; wxMediaState GetState() override; wxSize GetVideoSize() const override; private: void teardown(bool notify); void report(Status status); void bind_data_channel(const std::shared_ptr& dc); void on_ready(std::vector servers); void on_answer(std::string sdp); void on_ice(std::string candidate, std::string mid); void on_unavailable(CameraUnavailableReason reason, std::string detail); void decode_loop(); void enqueue_jpeg(std::vector jpeg); void deliver_jpeg(std::vector jpeg); mutable std::mutex m_mutex; std::condition_variable m_cond; std::deque> m_jpeg_queue; // Remote candidates can arrive before the answer; libdatachannel rejects // addRemoteCandidate until a remote description is set, so buffer them. std::vector> m_pending_candidates; bool m_remote_description_set = false; std::unique_ptr m_pending_signaling; std::unique_ptr m_signaling; std::shared_ptr m_peer_connection; std::shared_ptr m_data_channel; std::thread m_decode_thread; std::atomic m_alive{false}; std::atomic m_epoch{0}; wxMediaState m_state = static_cast(3); wxSize m_video_size = wxDefaultSize; std::function m_frame_sink; std::function m_on_status; bool m_has_frame = false; std::chrono::steady_clock::time_point m_last_frame_time{}; }; }} // namespace Slic3r::GUI