19 #include <api/audio_codecs/builtin_audio_decoder_factory.h>
20 #include <api/audio_codecs/builtin_audio_encoder_factory.h>
21 #include <api/rtc_event_log/rtc_event_log_factory.h>
22 #include <api/task_queue/default_task_queue_factory.h>
23 #include <api/video_codecs/builtin_video_decoder_factory.h>
24 #include <api/video_codecs/builtin_video_encoder_factory.h>
25 #include <media/engine/webrtc_media_engine.h>
26 #include <modules/audio_device/include/fake_audio_device.h>
27 #include <p2p/client/basic_port_allocator.h>
39 namespace visualization {
40 namespace webrtc_server {
61 std::size_t pos = url.find_first_of(
':');
62 if (pos != std::string::npos) {
63 std::string protocol = url.substr(0, pos);
64 std::string uri = url.substr(pos + 1);
65 std::string credentials;
67 std::size_t pos = uri.rfind(
'@');
68 if (pos != std::string::npos) {
69 credentials = uri.substr(0, pos);
70 uri = uri.substr(pos + 1);
72 srv.
url = protocol +
":" + uri;
74 if (!credentials.empty()) {
75 pos = credentials.find(
':');
76 if (pos == std::string::npos) {
77 srv.
user = credentials;
79 srv.
user = credentials.substr(0, pos);
80 srv.
pass = credentials.substr(pos + 1);
88 static webrtc::PeerConnectionFactoryDependencies
90 webrtc::PeerConnectionFactoryDependencies dependencies;
91 dependencies.network_thread =
nullptr;
92 dependencies.worker_thread = rtc::Thread::Current();
93 dependencies.signaling_thread =
nullptr;
94 dependencies.call_factory = webrtc::CreateCallFactory();
95 dependencies.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory();
96 dependencies.event_log_factory =
97 absl::make_unique<webrtc::RtcEventLogFactory>(
98 dependencies.task_queue_factory.get());
100 cricket::MediaEngineDependencies media_dependencies;
101 media_dependencies.task_queue_factory =
102 dependencies.task_queue_factory.get();
105 rtc::scoped_refptr<webrtc::AudioDeviceModule> audio_device_module(
106 new webrtc::FakeAudioDeviceModule());
107 media_dependencies.adm = std::move(audio_device_module);
108 media_dependencies.audio_encoder_factory =
109 webrtc::CreateBuiltinAudioEncoderFactory();
110 media_dependencies.audio_decoder_factory =
111 webrtc::CreateBuiltinAudioDecoderFactory();
112 media_dependencies.audio_processing =
113 webrtc::AudioProcessingBuilder().Create();
115 media_dependencies.video_encoder_factory =
116 webrtc::CreateBuiltinVideoEncoderFactory();
117 media_dependencies.video_decoder_factory =
118 webrtc::CreateBuiltinVideoDecoderFactory();
120 dependencies.media_engine =
121 cricket::CreateMediaEngine(std::move(media_dependencies));
127 const std::list<std::string> &ice_server_list,
128 const Json::Value &config,
129 const std::string &publish_filter,
130 const std::string &webrtc_udp_port_range)
131 : task_queue_factory_(webrtc::CreateDefaultTaskQueueFactory()),
132 peer_connection_factory_(webrtc::CreateModularPeerConnectionFactory(
134 ice_server_list_(ice_server_list),
136 publish_filter_(publish_filter) {
141 func_[
"/api/getMediaList"] = [
this](
const struct mg_request_info *req_info,
142 const Json::Value &in) -> Json::Value {
147 func_[
"/api/getIceServers"] = [
this](
const struct mg_request_info *req_info,
148 const Json::Value &in) -> Json::Value {
153 func_[
"/api/call"] = [
this](
const struct mg_request_info *req_info,
154 const Json::Value &in) -> Json::Value {
159 if (req_info->query_string) {
160 CivetServer::getParam(req_info->query_string,
"peerid", peerid);
161 CivetServer::getParam(req_info->query_string,
"url", url);
162 CivetServer::getParam(req_info->query_string,
"options", options);
164 return this->
Call(peerid, url, options, in);
167 func_[
"/api/getIceCandidate"] =
168 [
this](
const struct mg_request_info *req_info,
169 const Json::Value &in) -> Json::Value {
172 if (req_info->query_string) {
173 CivetServer::getParam(req_info->query_string,
"peerid", peerid);
178 func_[
"/api/addIceCandidate"] =
179 [
this](
const struct mg_request_info *req_info,
180 const Json::Value &in) -> Json::Value {
183 if (req_info->query_string) {
184 CivetServer::getParam(req_info->query_string,
"peerid", peerid);
189 func_[
"/api/hangup"] = [
this](
const struct mg_request_info *req_info,
190 const Json::Value &in) -> Json::Value {
193 if (req_info->query_string) {
194 CivetServer::getParam(req_info->query_string,
"peerid", peerid);
196 return this->
HangUp(peerid);
204 Json::Value value(Json::arrayValue);
206 for (
const std::string &window_uid :
209 media[
"video"] = window_uid;
220 Json::Value urls(Json::arrayValue);
224 Json::Value urlList(Json::arrayValue);
226 urlList.append(srv.
url);
227 server[
"urls"] = urlList;
228 if (srv.
user.length() > 0) server[
"username"] = srv.
user;
229 if (srv.
pass.length() > 0) server[
"credential"] = srv.
pass;
233 Json::Value iceServers;
234 iceServers[
"iceServers"] = urls;
240 rtc::scoped_refptr<webrtc::PeerConnectionInterface>
242 rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection;
245 peer_connection = it->second->GetPeerConnection();
247 return peer_connection;
252 const std::string &peerid,
const Json::Value &json_message) {
255 int sdp_mlineindex = 0;
259 !rtc::GetIntFromJsonObject(json_message,
266 std::unique_ptr<webrtc::IceCandidateInterface> candidate(
267 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp,
269 if (!candidate.get()) {
272 bool dc_ready =
false;
274 std::lock_guard<std::mutex> mutex_lock(
280 "DataChannels ready. Skipping AddIceCandidate.");
282 std::lock_guard<std::mutex> mutex_lock(
284 rtc::scoped_refptr<webrtc::PeerConnectionInterface>
286 if (peer_connection) {
287 if (!peer_connection->AddIceCandidate(candidate.get())) {
289 "Failed to apply the received candidate.");
306 const std::string &window_uid,
307 const std::string &options,
308 const Json::Value &json_message) {
314 if (!rtc::GetStringFromJsonObject(json_message,
316 !rtc::GetStringFromJsonObject(json_message,
320 PeerConnectionObserver *peer_connection_observer =
322 if (!peer_connection_observer) {
324 }
else if (!peer_connection_observer->GetPeerConnection().get()) {
326 delete peer_connection_observer;
328 rtc::scoped_refptr<webrtc::PeerConnectionInterface>
330 peer_connection_observer->GetPeerConnection();
332 peer_connection->local_streams()->count(),
333 peer_connection->remote_streams()->count());
337 std::lock_guard<std::mutex> mutex_lock(
340 std::pair<std::string, PeerConnectionObserver *>(
341 peerid, peer_connection_observer));
344 std::lock_guard<std::mutex> mutex_lock(
351 webrtc::SessionDescriptionInterface *session_description(
352 webrtc::CreateSessionDescription(
type, sdp,
nullptr));
353 if (!session_description) {
355 "Can't parse received session description message. "
356 "Cannot create session description.");
358 std::promise<const webrtc::SessionDescriptionInterface *>
360 peer_connection->SetRemoteDescription(
361 SetSessionDescriptionObserver::Create(peer_connection,
363 session_description);
365 std::future<const webrtc::SessionDescriptionInterface *>
366 remote_future = remote_promise.get_future();
367 if (remote_future.wait_for(std::chrono::milliseconds(5000)) ==
368 std::future_status::ready) {
372 "remote_description is nullptr. Setting remote "
373 "description failed.");
378 if (!this->
AddStreams(peer_connection, window_uid, options)) {
384 webrtc::PeerConnectionInterface::RTCOfferAnswerOptions rtc_options;
385 std::promise<const webrtc::SessionDescriptionInterface *>
387 peer_connection->CreateAnswer(
388 CreateSessionDescriptionObserver::Create(peer_connection,
393 std::future<const webrtc::SessionDescriptionInterface *>
394 local_future = local_promise.get_future();
395 if (local_future.wait_for(std::chrono::milliseconds(5000)) ==
396 std::future_status::ready) {
398 const webrtc::SessionDescriptionInterface *desc =
402 desc->ToString(&sdp);
418 bool still_used =
false;
420 rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection =
421 it.second->GetPeerConnection();
422 rtc::scoped_refptr<webrtc::StreamCollectionInterface> local_streams(
423 peer_connection->local_streams());
424 for (
unsigned int i = 0; i < local_streams->count(); i++) {
425 if (local_streams->at(i)->id() == window_uid) {
437 PeerConnectionObserver *pc_observer =
nullptr;
442 pc_observer = it->second;
447 std::lock_guard<std::mutex> mutex_lock(
459 rtc::scoped_refptr<webrtc::PeerConnectionInterface>
460 peer_connection = pc_observer->GetPeerConnection();
462 rtc::scoped_refptr<webrtc::StreamCollectionInterface> local_streams(
463 peer_connection->local_streams());
464 for (
unsigned int i = 0; i < local_streams->count(); i++) {
465 auto stream = local_streams->at(i);
467 std::string window_uid = stream->id();
470 std::lock_guard<std::mutex> mlock(
479 peer_connection->RemoveStream(stream);
493 const std::map<std::string, HttpServerRequestHandler::HttpFunction>
500 const std::string &peerid) {
505 PeerConnectionObserver *obs = it->second;
507 value = obs->GetIceCandidateList();
521 PeerConnectionManager::PeerConnectionObserver *
523 webrtc::PeerConnectionInterface::RTCConfiguration config;
525 webrtc::PeerConnectionInterface::IceServer server;
527 server.uri = srv.
url;
528 server.username = srv.
user;
529 server.password = srv.
pass;
530 config.servers.push_back(server);
536 int max_port = 65535;
539 if (std::getline(is, port,
':')) {
540 min_port = std::stoi(port);
541 if (std::getline(is, port,
':')) {
542 max_port = std::stoi(port);
545 std::unique_ptr<cricket::PortAllocator> port_allocator(
546 new cricket::BasicPortAllocator(
new rtc::BasicNetworkManager()));
547 port_allocator->SetPortRange(min_port, max_port);
551 PeerConnectionObserver *obs =
new PeerConnectionObserver(
552 this, peerid, config, std::move(port_allocator));
562 rtc::scoped_refptr<BitmapTrackSourceInterface>
564 const std::string &window_uid,
565 const std::map<std::string, std::string> &opts) {
566 std::string video = window_uid;
568 video =
config_[video][
"video"].asString();
576 webrtc::PeerConnectionInterface *peer_connection,
577 const std::string &window_uid,
578 const std::string &options) {
583 std::string optstring = options;
584 if (
config_.isMember(window_uid)) {
585 std::string urlopts =
config_[window_uid][
"options"].asString();
586 if (options.empty()) {
588 }
else if (options.find_first_of(
"&") == 0) {
589 optstring = urlopts + options;
596 std::istringstream is(optstring);
597 std::map<std::string, std::string> opts;
598 std::string key, value;
599 while (std::getline(std::getline(is, key,
'='), value,
'&')) {
603 std::string video = window_uid;
605 video =
config_[video][
"video"].asString();
609 if (opts.find(
"bitrate") != opts.end()) {
610 int bitrate = std::stoi(opts.at(
"bitrate"));
612 webrtc::BitrateSettings bitrate_param;
613 bitrate_param.min_bitrate_bps = absl::optional<int>(bitrate / 2);
614 bitrate_param.start_bitrate_bps = absl::optional<int>(bitrate);
615 bitrate_param.max_bitrate_bps = absl::optional<int>(bitrate * 2);
616 peer_connection->SetBitrate(bitrate_param);
619 bool existing_stream =
false;
626 if (!existing_stream) {
628 rtc::scoped_refptr<BitmapTrackSourceInterface> video_source(
639 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
645 rtc::scoped_refptr<BitmapTrackSourceInterface> video_source =
647 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track;
652 rtc::scoped_refptr<BitmapTrackSourceInterface> videoScaled =
656 window_uid +
"_video", videoScaled);
659 if ((video_track) && (!stream->AddTrack(video_track))) {
661 "Adding VideoTrack to MediaStream failed.");
664 if (!peer_connection->AddStream(stream)) {
680 void PeerConnectionManager::PeerConnectionObserver::OnIceCandidate(
681 const webrtc::IceCandidateInterface *candidate) {
683 if (!candidate->ToString(&sdp)) {
686 Json::Value json_message;
689 candidate->sdp_mline_index();
691 ice_candidate_list_.append(json_message);
695 rtc::scoped_refptr<BitmapTrackSourceInterface>
715 const std::string &window_uid) {
718 std::set<std::string> peerids;
723 for (
const std::string &peerid : peerids) {
733 const std::shared_ptr<core::Tensor> &im) {
737 rtc::scoped_refptr<BitmapTrackSourceInterface> video_track_source =
739 if (video_track_source) {
743 video_track_source->OnFrame(im);
static rtc::scoped_refptr< BitmapTrackSourceInterface > Create(const std::string &window_uid, const std::map< std::string, std::string > &opts)
std::mutex window_uid_to_track_source_mutex_
std::mutex peerid_to_connection_mutex_
const Json::Value GetMediaList()
std::mutex peerid_data_channel_mutex_
std::mutex window_uid_to_peerids_mutex_
void OnFrame(const std::string &window_uid, const std::shared_ptr< core::Tensor > &im)
std::list< std::string > ice_server_list_
virtual ~PeerConnectionManager()
void CloseWindowConnections(const std::string &window_uid)
std::unordered_map< std::string, std::set< std::string > > window_uid_to_peerids_
PeerConnectionObserver * CreatePeerConnection(const std::string &peerid)
const Json::Value GetIceCandidateList(const std::string &peerid)
const Json::Value GetIceServers()
const Json::Value config_
rtc::scoped_refptr< webrtc::PeerConnectionFactoryInterface > peer_connection_factory_
rtc::scoped_refptr< BitmapTrackSourceInterface > GetVideoTrackSource(const std::string &window_uid)
std::unordered_map< std::string, rtc::scoped_refptr< BitmapTrackSourceInterface > > window_uid_to_track_source_
bool AddStreams(webrtc::PeerConnectionInterface *peer_connection, const std::string &window_uid, const std::string &options)
std::map< std::string, HttpServerRequestHandler::HttpFunction > func_
std::unordered_set< std::string > peerid_data_channel_ready_
PeerConnectionManager(const std::list< std::string > &ice_server_list, const Json::Value &config, const std::string &publish_filter, const std::string &webrtc_udp_port_range)
std::unordered_map< std::string, PeerConnectionObserver * > peerid_to_connection_
std::unordered_map< std::string, std::string > peerid_to_window_uid_
const Json::Value Call(const std::string &peerid, const std::string &window_uid, const std::string &options, const Json::Value &json_message)
std::string webrtc_port_range_
const std::map< std::string, HttpServerRequestHandler::HttpFunction > GetHttpApi()
rtc::scoped_refptr< webrtc::PeerConnectionInterface > GetPeerConnection(const std::string &peerid)
bool InitializePeerConnection()
rtc::scoped_refptr< BitmapTrackSourceInterface > CreateVideoSource(const std::string &window_uid, const std::map< std::string, std::string > &opts)
bool WindowStillUsed(const std::string &window_uid)
const Json::Value HangUp(const std::string &peerid)
void SendInitFramesToPeer(const std::string &peerid)
const Json::Value AddIceCandidate(const std::string &peerid, const Json::Value &json_message)
static rtc::scoped_refptr< VideoFilter > Create(rtc::scoped_refptr< BitmapTrackSourceInterface > video_source, const std::map< std::string, std::string > &opts)
static std::shared_ptr< WebRTCWindowSystem > GetInstance()
static webrtc::PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies()
const char k_session_description_sdp_name[]
const char k_candidate_sdp_mid_name[]
static IceServer GetIceServerFromUrl(const std::string &url)
const char k_candidate_sdp_mline_index_name[]
const char k_candidate_sdp_name[]
const char k_session_description_type_name[]
Generic file read and write utility for python interface.