Open3D (C++ API)  0.19.0
Loading...
Searching...
No Matches
PeerConnectionManager.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2024 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7// ----------------------------------------------------------------------------
8// Contains source code from
9// https://github.com/mpromonet/webrtc-streamer
10//
11// This software is in the public domain, furnished "as is", without technical
12// support, and with no warranty, express or implied, as to its usefulness for
13// any purpose.
14// ----------------------------------------------------------------------------
15//
16// This is a private header. It shall be hidden from Open3D's public API. Do not
17// put this in Open3D.h.in.
18
19#pragma once
20
21#include <api/field_trials.h>
22#include <api/peer_connection_interface.h>
23#include <api/scoped_refptr.h>
24#include <api/stats/rtc_stats.h>
25#include <rtc_base/ref_counted_object.h>
26#include <rtc_base/strings/json.h>
27
28#include <atomic>
29#include <condition_variable>
30#include <future>
31#include <mutex>
32#include <regex>
33#include <string>
34#include <thread>
35#include <unordered_map>
36
40
41namespace webrtc {
42class Thread;
43}
44
45namespace open3d {
46namespace visualization {
47namespace webrtc_server {
48
84 class VideoSink : public webrtc::VideoSinkInterface<webrtc::VideoFrame> {
85 public:
86 VideoSink(webrtc::VideoTrackInterface* track) : track_(track) {
87 track_->AddOrUpdateSink(this, webrtc::VideoSinkWants());
88 }
89 virtual ~VideoSink() { track_->RemoveSink(this); }
90
91 // VideoSinkInterface implementation
92 virtual void OnFrame(const webrtc::VideoFrame& video_frame) {
93 webrtc::scoped_refptr<webrtc::I420BufferInterface> buffer(
94 video_frame.video_frame_buffer()->ToI420());
95 utility::LogDebug("[{}] frame: {}x{}", OPEN3D_FUNCTION,
96 buffer->height(), buffer->width());
97 }
98
99 protected:
100 webrtc::scoped_refptr<webrtc::VideoTrackInterface> track_;
101 };
102
103 class SetSessionDescriptionObserver
104 : public webrtc::SetSessionDescriptionObserver {
105 public:
106 static SetSessionDescriptionObserver* Create(
107 webrtc::PeerConnectionInterface* pc,
108 std::promise<const webrtc::SessionDescriptionInterface*>&
109 promise) {
110 return new webrtc::RefCountedObject<SetSessionDescriptionObserver>(
111 pc, promise);
112 }
113 virtual void OnSuccess() {
114 std::string sdp;
115 if (pc_->local_description()) {
116 promise_.set_value(pc_->local_description());
117 pc_->local_description()->ToString(&sdp);
118 } else if (pc_->remote_description()) {
119 promise_.set_value(pc_->remote_description());
120 pc_->remote_description()->ToString(&sdp);
121 }
122 }
123 virtual void OnFailure(webrtc::RTCError error) {
124 utility::LogWarning("{}", error.message());
125 promise_.set_value(nullptr);
126 }
127
128 protected:
129 SetSessionDescriptionObserver(
130 webrtc::PeerConnectionInterface* pc,
131 std::promise<const webrtc::SessionDescriptionInterface*>&
132 promise)
133 : pc_(pc), promise_(promise) {};
134
135 private:
136 webrtc::PeerConnectionInterface* pc_;
137 std::promise<const webrtc::SessionDescriptionInterface*>& promise_;
138 };
139
140 class CreateSessionDescriptionObserver
141 : public webrtc::CreateSessionDescriptionObserver {
142 public:
143 static CreateSessionDescriptionObserver* Create(
144 webrtc::PeerConnectionInterface* pc,
145 std::promise<const webrtc::SessionDescriptionInterface*>&
146 promise) {
147 return new webrtc::RefCountedObject<
148 CreateSessionDescriptionObserver>(pc, promise);
149 }
150 virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) {
151 std::string sdp;
152 desc->ToString(&sdp);
153 pc_->SetLocalDescription(
154 SetSessionDescriptionObserver::Create(pc_, promise_), desc);
155 }
156 virtual void OnFailure(webrtc::RTCError error) {
157 utility::LogWarning("{}", error.message());
158 promise_.set_value(nullptr);
159 }
160
161 protected:
162 CreateSessionDescriptionObserver(
163 webrtc::PeerConnectionInterface* pc,
164 std::promise<const webrtc::SessionDescriptionInterface*>&
165 promise)
166 : pc_(pc), promise_(promise) {};
167
168 private:
169 webrtc::PeerConnectionInterface* pc_;
170 std::promise<const webrtc::SessionDescriptionInterface*>& promise_;
171 };
172
173 class PeerConnectionStatsCollectorCallback
174 : public webrtc::RTCStatsCollectorCallback {
175 public:
176 PeerConnectionStatsCollectorCallback() {}
177 void clearReport() { report_.clear(); }
178 Json::Value getReport() { return report_; }
179
180 protected:
181 virtual void OnStatsDelivered(
182 const webrtc::scoped_refptr<const webrtc::RTCStatsReport>&
183 report) {
184 for (const webrtc::RTCStats& stats : *report) {
185 Json::Value stats_members;
186 for (const webrtc::Attribute& attribute : stats.Attributes()) {
187 stats_members[attribute.name()] = attribute.ToString();
188 }
189 report_[stats.id()] = stats_members;
190 }
191 }
192
193 Json::Value report_;
194 };
195
196 class DataChannelObserver : public webrtc::DataChannelObserver {
197 public:
198 DataChannelObserver(PeerConnectionManager* peer_connection_manager,
199 webrtc::scoped_refptr<webrtc::DataChannelInterface>
200 data_channel,
201 const std::string& peerid)
202 : peer_connection_manager_(peer_connection_manager),
203 data_channel_(data_channel),
204 peerid_(peerid) {
205 data_channel_->RegisterObserver(this);
206 }
207 virtual ~DataChannelObserver() { data_channel_->UnregisterObserver(); }
208
209 // DataChannelObserver interface
210 virtual void OnStateChange() {
211 // Useful to know when the data channel is established.
212 const std::string label = data_channel_->label();
213 const std::string state =
214 webrtc::DataChannelInterface::DataStateString(
215 data_channel_->state());
216 utility::LogDebug(
217 "DataChannelObserver::OnStateChange label: {}, state: {}, "
218 "peerid: {}",
219 label, state, peerid_);
220 std::string msg(label + " " + state);
221 webrtc::DataBuffer buffer(msg);
222 data_channel_->Send(buffer);
223 // ClientDataChannel is established after ServerDataChannel. Once
224 // ClientDataChannel is established, we need to send initial frames
225 // to the client such that the video is not empty. Afterwards,
226 // video frames will only be sent when the GUI redraws.
227 if (label == "ClientDataChannel" && state == "open") {
228 {
229 std::lock_guard<std::mutex> mutex_lock(
230 peer_connection_manager_
232 peer_connection_manager_->peerid_data_channel_ready_.insert(
233 peerid_);
234 }
235 peer_connection_manager_->SendInitFramesToPeer(peerid_);
236 }
237 if (label == "ClientDataChannel" &&
238 (state == "closed" || state == "closing")) {
239 std::lock_guard<std::mutex> mutex_lock(
240 peer_connection_manager_->peerid_data_channel_mutex_);
241 peer_connection_manager_->peerid_data_channel_ready_.erase(
242 peerid_);
243 }
244 }
245 virtual void OnMessage(const webrtc::DataBuffer& buffer) {
246 std::string msg((const char*)buffer.data.data(),
247 buffer.data.size());
248 utility::LogDebug("DataChannelObserver::OnMessage: {}, msg: {}.",
249 data_channel_->label(), msg);
250 std::string reply =
251 WebRTCWindowSystem::GetInstance()->OnDataChannelMessage(
252 msg);
253 if (!reply.empty()) {
254 webrtc::DataBuffer buffer(reply);
255 data_channel_->Send(buffer);
256 }
257 }
258
259 protected:
260 PeerConnectionManager* peer_connection_manager_;
261 webrtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
262 const std::string peerid_;
263 };
264
265 class PeerConnectionObserver : public webrtc::PeerConnectionObserver {
266 public:
267 PeerConnectionObserver(PeerConnectionManager* peer_connection_manager,
268 const std::string& peerid);
269
270 void Initialize(webrtc::scoped_refptr<webrtc::PeerConnectionInterface>
271 peer_connection);
272
273 virtual ~PeerConnectionObserver() {
274 delete local_channel_;
275 delete remote_channel_;
276 if (pc_.get()) {
277 // warning: pc->close call OnIceConnectionChange
278 deleting_ = true;
279 pc_->Close();
280 }
281 }
282
283 Json::Value GetIceCandidateList() { return ice_candidate_list_; }
284
285 Json::Value GetStats() {
286 stats_callback_->clearReport();
287 pc_->GetStats(stats_callback_.get());
288 int count = 10;
289 while ((stats_callback_->getReport().empty()) && (--count > 0)) {
290 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
291 }
292 return Json::Value(stats_callback_->getReport());
293 };
294
295 webrtc::scoped_refptr<webrtc::PeerConnectionInterface>
296 GetPeerConnection() {
297 return pc_;
298 };
299
300 // PeerConnectionObserver interface
301 virtual void OnAddStream(
302 webrtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
303 utility::LogDebug("[{}] GetVideoTracks().size(): {}.",
304 OPEN3D_FUNCTION, stream->GetVideoTracks().size());
305 webrtc::VideoTrackVector videoTracks = stream->GetVideoTracks();
306 if (videoTracks.size() > 0) {
307 video_sink_.reset(new VideoSink(videoTracks.at(0).get()));
308 }
309 }
310 virtual void OnRemoveStream(
311 webrtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
312 video_sink_.reset();
313 }
314 virtual void OnDataChannel(
315 webrtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
316 utility::LogDebug(
317 "PeerConnectionObserver::OnDataChannel peerid: {}",
318 peerid_);
319 remote_channel_ = new DataChannelObserver(peer_connection_manager_,
320 channel, peerid_);
321 }
322 virtual void OnRenegotiationNeeded() {
323 std::lock_guard<std::mutex> mutex_lock(
324 peer_connection_manager_->peerid_data_channel_mutex_);
325 peer_connection_manager_->peerid_data_channel_ready_.erase(peerid_);
326 utility::LogDebug(
327 "PeerConnectionObserver::OnRenegotiationNeeded peerid: {}",
328 peerid_);
329 }
330 virtual void OnIceCandidate(
331 const webrtc::IceCandidateInterface* candidate);
332
333 virtual void OnSignalingChange(
334 webrtc::PeerConnectionInterface::SignalingState state) {
335 utility::LogDebug("state: {}, peerid: {}", state, peerid_);
336 }
337 virtual void OnIceConnectionChange(
338 webrtc::PeerConnectionInterface::IceConnectionState state) {
339 if ((state ==
340 webrtc::PeerConnectionInterface::kIceConnectionFailed) ||
341 (state ==
342 webrtc::PeerConnectionInterface::kIceConnectionClosed)) {
343 ice_candidate_list_.clear();
344 if (!deleting_) {
345 std::thread([this]() {
346 peer_connection_manager_->HangUp(peerid_);
347 }).detach();
348 }
349 }
350 }
351
352 virtual void OnIceGatheringChange(
353 webrtc::PeerConnectionInterface::IceGatheringState) {}
354
355 private:
356 PeerConnectionManager* peer_connection_manager_;
357 const std::string peerid_;
358 webrtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_;
359 DataChannelObserver* local_channel_;
360 DataChannelObserver* remote_channel_;
361 Json::Value ice_candidate_list_;
362 webrtc::scoped_refptr<PeerConnectionStatsCollectorCallback>
363 stats_callback_;
364 std::unique_ptr<VideoSink> video_sink_;
365 bool deleting_;
366 };
367
368public:
369 PeerConnectionManager(const std::list<std::string>& ice_server_list,
370 const Json::Value& config,
371 const std::string& publish_filter,
372 const std::string& webrtc_udp_port_range);
373 virtual ~PeerConnectionManager();
374
376 const std::map<std::string, HttpServerRequestHandler::HttpFunction>
377 GetHttpApi();
378
379 const Json::Value GetIceCandidateList(const std::string& peerid);
380 const Json::Value AddIceCandidate(const std::string& peerid,
381 const Json::Value& json_message);
382 const Json::Value GetMediaList();
383 const Json::Value HangUp(const std::string& peerid);
384 const Json::Value Call(const std::string& peerid,
385 const std::string& window_uid,
386 const std::string& options,
387 const Json::Value& json_message);
388 const Json::Value GetIceServers();
389
390 void SendInitFramesToPeer(const std::string& peerid);
391
392 void CloseWindowConnections(const std::string& window_uid);
393
394 void OnFrame(const std::string& window_uid,
395 const std::shared_ptr<core::Tensor>& im);
396
397protected:
398 webrtc::scoped_refptr<BitmapTrackSourceInterface> GetVideoTrackSource(
399 const std::string& window_uid);
400 PeerConnectionObserver* CreatePeerConnection(const std::string& peerid);
401 bool AddStreams(webrtc::PeerConnectionInterface* peer_connection,
402 const std::string& window_uid,
403 const std::string& options);
404 webrtc::scoped_refptr<BitmapTrackSourceInterface> CreateVideoSource(
405 const std::string& window_uid,
406 const std::map<std::string, std::string>& opts);
407 bool WindowStillUsed(const std::string& window_uid);
408 webrtc::scoped_refptr<webrtc::PeerConnectionInterface> GetPeerConnection(
409 const std::string& peerid);
410
411protected:
412 std::unique_ptr<webrtc::FieldTrials> field_trials_;
413 webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
415
416 // Each peer has exactly one connection.
417 std::unordered_map<std::string, PeerConnectionObserver*>
420 // Set of peerids with data channel ready for communication
421 std::unordered_set<std::string> peerid_data_channel_ready_;
423
424 // Each Window has exactly one TrackSource.
425 std::unordered_map<std::string,
426 webrtc::scoped_refptr<BitmapTrackSourceInterface>>
429
430 // Each Window can be connected to zero, one or more peers.
431 std::unordered_map<std::string, std::set<std::string>>
433 std::unordered_map<std::string, std::string> peerid_to_window_uid_;
434 // Shared by window_uid_to_peerids_ and peerid_to_window_uid_.
436
437 std::list<std::string> ice_server_list_;
438 const Json::Value config_;
439 const std::regex publish_filter_;
440 std::map<std::string, HttpServerRequestHandler::HttpFunction> func_;
442
443 // Async encoder thread: decouples the render thread from the blocking
444 // libyuv + WebRTC encode path. OnFrame() posts the latest frame per window;
445 // the thread drains the map and posts video_track_source->OnFrame() to the
446 // WebRTC worker thread.
447 std::unordered_map<std::string, std::shared_ptr<core::Tensor>>
450 std::condition_variable pending_frames_cv_;
451 std::atomic<bool> encoder_running_{false};
452 std::thread encoder_thread_;
453 // WebRTC worker thread (PeerConnectionFactoryDependencies::worker_thread).
454 webrtc::Thread* webrtc_worker_thread_ = nullptr;
455
456 void EncoderThreadLoop();
457};
458
459} // namespace webrtc_server
460} // namespace visualization
461} // namespace open3d
462
463namespace fmt {
464
465template <>
466struct formatter<webrtc::PeerConnectionInterface::SignalingState> {
467 template <typename FormatContext>
468 auto format(const webrtc::PeerConnectionInterface::SignalingState& state,
469 FormatContext& ctx) const -> decltype(ctx.out()) {
470 using namespace webrtc;
471 const char* text = nullptr;
472 switch (state) {
473 case PeerConnectionInterface::SignalingState::kStable:
474 text = "kStable";
475 break;
476 case PeerConnectionInterface::SignalingState::kHaveLocalOffer:
477 text = "kHaveLocalOffer";
478 break;
479 case PeerConnectionInterface::SignalingState::kHaveLocalPrAnswer:
480 text = "kHaveLocalPrAnswer";
481 break;
482 case PeerConnectionInterface::SignalingState::kHaveRemoteOffer:
483 text = "kHaveRemoteOffer";
484 break;
485 case PeerConnectionInterface::SignalingState::kHaveRemotePrAnswer:
486 text = "kHaveRemotePrAnswer";
487 break;
488 case PeerConnectionInterface::SignalingState::kClosed:
489 text = "kClosed";
490 break;
491 default:
492 text = "unknown";
493 }
494 return fmt::format_to(ctx.out(), "{}", text);
495 }
496
497 template <typename ParseContext>
498 constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
499 return ctx.begin();
500 }
501};
502
503} // namespace fmt
filament::Texture::InternalFormat format
Definition FilamentResourceManager.cpp:202
#define OPEN3D_FUNCTION
Definition Macro.h:43
const Json::Value AddIceCandidate(const std::string &peerid, const Json::Value &json_message)
Definition PeerConnectionManager.cpp:270
std::mutex peerid_data_channel_mutex_
Definition PeerConnectionManager.h:422
webrtc::scoped_refptr< BitmapTrackSourceInterface > GetVideoTrackSource(const std::string &window_uid)
Definition PeerConnectionManager.cpp:740
PeerConnectionObserver * CreatePeerConnection(const std::string &peerid)
Definition PeerConnectionManager.cpp:560
virtual ~PeerConnectionManager()
Definition PeerConnectionManager.cpp:214
std::mutex window_uid_to_peerids_mutex_
Definition PeerConnectionManager.h:435
std::condition_variable pending_frames_cv_
Definition PeerConnectionManager.h:450
webrtc::scoped_refptr< webrtc::PeerConnectionInterface > GetPeerConnection(const std::string &peerid)
Definition PeerConnectionManager.cpp:260
bool WindowStillUsed(const std::string &window_uid)
Definition PeerConnectionManager.cpp:444
std::unique_ptr< webrtc::FieldTrials > field_trials_
Definition PeerConnectionManager.h:412
webrtc::scoped_refptr< BitmapTrackSourceInterface > CreateVideoSource(const std::string &window_uid, const std::map< std::string, std::string > &opts)
Definition PeerConnectionManager.cpp:610
std::mutex peerid_to_connection_mutex_
Definition PeerConnectionManager.h:419
const Json::Value Call(const std::string &peerid, const std::string &window_uid, const std::string &options, const Json::Value &json_message)
Definition PeerConnectionManager.cpp:324
std::unordered_map< std::string, std::set< std::string > > window_uid_to_peerids_
Definition PeerConnectionManager.h:432
bool InitializePeerConnection()
Definition PeerConnectionManager.cpp:527
void SendInitFramesToPeer(const std::string &peerid)
Definition PeerConnectionManager.cpp:752
std::unordered_map< std::string, webrtc::scoped_refptr< BitmapTrackSourceInterface > > window_uid_to_track_source_
Definition PeerConnectionManager.h:427
std::unordered_map< std::string, std::string > peerid_to_window_uid_
Definition PeerConnectionManager.h:433
const Json::Value GetIceCandidateList(const std::string &peerid)
Definition PeerConnectionManager.cpp:510
const Json::Value HangUp(const std::string &peerid)
Definition PeerConnectionManager.cpp:455
std::unordered_map< std::string, std::shared_ptr< core::Tensor > > pending_frames_
Definition PeerConnectionManager.h:448
void EncoderThreadLoop()
Definition PeerConnectionManager.cpp:779
const Json::Value GetMediaList()
Definition PeerConnectionManager.cpp:222
void OnFrame(const std::string &window_uid, const std::shared_ptr< core::Tensor > &im)
Definition PeerConnectionManager.cpp:813
std::list< std::string > ice_server_list_
Definition PeerConnectionManager.h:437
const Json::Value GetIceServers()
Definition PeerConnectionManager.cpp:236
std::thread encoder_thread_
Definition PeerConnectionManager.h:452
const std::map< std::string, HttpServerRequestHandler::HttpFunction > GetHttpApi()
Definition PeerConnectionManager.cpp:505
std::map< std::string, HttpServerRequestHandler::HttpFunction > func_
Definition PeerConnectionManager.h:440
std::string webrtc_port_range_
Definition PeerConnectionManager.h:441
std::unordered_map< std::string, PeerConnectionObserver * > peerid_to_connection_
Definition PeerConnectionManager.h:418
webrtc::Thread * webrtc_worker_thread_
Definition PeerConnectionManager.h:454
void CloseWindowConnections(const std::string &window_uid)
Definition PeerConnectionManager.cpp:758
std::unordered_set< std::string > peerid_data_channel_ready_
Definition PeerConnectionManager.h:421
const std::regex publish_filter_
Definition PeerConnectionManager.h:439
bool AddStreams(webrtc::PeerConnectionInterface *peer_connection, const std::string &window_uid, const std::string &options)
Definition PeerConnectionManager.cpp:622
webrtc::scoped_refptr< webrtc::PeerConnectionFactoryInterface > peer_connection_factory_
Definition PeerConnectionManager.h:414
std::mutex window_uid_to_track_source_mutex_
Definition PeerConnectionManager.h:428
std::atomic< bool > encoder_running_
Definition PeerConnectionManager.h:451
const Json::Value config_
Definition PeerConnectionManager.h:438
std::mutex pending_frames_mutex_
Definition PeerConnectionManager.h:449
static std::shared_ptr< WebRTCWindowSystem > GetInstance()
Definition WebRTCWindowSystem.cpp:112
int count
Definition FilePCD.cpp:43
Definition DLPack.h:678
Definition PinholeCameraIntrinsic.cpp:16
Definition PeerConnectionManager.h:41