mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 03:11:47 +00:00
feat: camera via webrtc
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include "IMediaController.hpp"
|
||||
#include "WebRtcFrameAssembler.hpp"
|
||||
|
||||
#include <wx/image.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace rtc {
|
||||
class DataChannel;
|
||||
class PeerConnection;
|
||||
class Track;
|
||||
}
|
||||
|
||||
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 StartSession 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<void(const wxImage&, wxSize)> frame_sink,
|
||||
std::function<void(Status)> on_status);
|
||||
~WebRtcMediaController() override;
|
||||
|
||||
void StartSession(std::unique_ptr<ICameraSignalingChannel> channel) override;
|
||||
void StopSession() override;
|
||||
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 { StopSession(); }
|
||||
wxMediaState GetState() override;
|
||||
wxSize GetVideoSize() const override;
|
||||
|
||||
private:
|
||||
void teardown(bool notify);
|
||||
void report(Status status);
|
||||
void bind_data_channel(const std::shared_ptr<rtc::DataChannel>& dc);
|
||||
void on_ready(std::vector<CameraIceServer> 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_chunk(std::vector<std::byte> chunk);
|
||||
void enqueue_nal(std::vector<std::byte> nal);
|
||||
void deliver_jpeg(std::vector<std::byte> jpeg);
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
std::condition_variable m_cond;
|
||||
std::deque<std::vector<std::byte>> m_chunk_queue;
|
||||
std::deque<std::vector<std::byte>> m_nal_queue;
|
||||
// Remote candidates can arrive before the answer; libdatachannel rejects
|
||||
// addRemoteCandidate until a remote description is set, so buffer them.
|
||||
std::vector<std::pair<std::string, std::string>> m_pending_candidates;
|
||||
bool m_remote_description_set = false;
|
||||
std::unique_ptr<ICameraSignalingChannel> m_signaling;
|
||||
std::shared_ptr<rtc::PeerConnection> m_peer_connection;
|
||||
std::shared_ptr<rtc::DataChannel> m_data_channel;
|
||||
std::shared_ptr<rtc::Track> m_video_track;
|
||||
std::thread m_decode_thread;
|
||||
std::atomic<bool> m_alive{false};
|
||||
std::atomic<std::uint64_t> m_epoch{0};
|
||||
wxMediaState m_state = static_cast<wxMediaState>(3);
|
||||
wxSize m_video_size = wxDefaultSize;
|
||||
std::function<void(const wxImage&, wxSize)> m_frame_sink;
|
||||
std::function<void(Status)> m_on_status;
|
||||
bool m_has_frame = false;
|
||||
std::chrono::steady_clock::time_point m_last_frame_time{};
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
Reference in New Issue
Block a user