1 /**
2  * Copyright (c) 2019-2021 Paul-Louis Ageneau
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "rtc.h"
20 #include "rtc.hpp"
21 
22 #include "impl/internals.hpp"
23 
24 #include <chrono>
25 #include <exception>
26 #include <mutex>
27 #include <type_traits>
28 #include <unordered_map>
29 #include <utility>
30 
31 using namespace rtc;
32 using namespace std::chrono_literals;
33 using std::chrono::milliseconds;
34 
35 namespace {
36 
37 std::unordered_map<int, shared_ptr<PeerConnection>> peerConnectionMap;
38 std::unordered_map<int, shared_ptr<DataChannel>> dataChannelMap;
39 std::unordered_map<int, shared_ptr<Track>> trackMap;
40 #if RTC_ENABLE_MEDIA
41 std::unordered_map<int, shared_ptr<MediaChainableHandler>> rtcpChainableHandlerMap;
42 std::unordered_map<int, shared_ptr<RtcpSrReporter>> rtcpSrReporterMap;
43 std::unordered_map<int, shared_ptr<RtpPacketizationConfig>> rtpConfigMap;
44 #endif
45 #if RTC_ENABLE_WEBSOCKET
46 std::unordered_map<int, shared_ptr<WebSocket>> webSocketMap;
47 std::unordered_map<int, shared_ptr<WebSocketServer>> webSocketServerMap;
48 #endif
49 std::unordered_map<int, void *> userPointerMap;
50 std::mutex mutex;
51 int lastId = 0;
52 
getUserPointer(int id)53 optional<void *> getUserPointer(int id) {
54 	std::lock_guard lock(mutex);
55 	auto it = userPointerMap.find(id);
56 	return it != userPointerMap.end() ? std::make_optional(it->second) : nullopt;
57 }
58 
setUserPointer(int i,void * ptr)59 void setUserPointer(int i, void *ptr) {
60 	std::lock_guard lock(mutex);
61 	userPointerMap[i] = ptr;
62 }
63 
getPeerConnection(int id)64 shared_ptr<PeerConnection> getPeerConnection(int id) {
65 	std::lock_guard lock(mutex);
66 	if (auto it = peerConnectionMap.find(id); it != peerConnectionMap.end())
67 		return it->second;
68 	else
69 		throw std::invalid_argument("PeerConnection ID does not exist");
70 }
71 
getDataChannel(int id)72 shared_ptr<DataChannel> getDataChannel(int id) {
73 	std::lock_guard lock(mutex);
74 	if (auto it = dataChannelMap.find(id); it != dataChannelMap.end())
75 		return it->second;
76 	else
77 		throw std::invalid_argument("DataChannel ID does not exist");
78 }
79 
getTrack(int id)80 shared_ptr<Track> getTrack(int id) {
81 	std::lock_guard lock(mutex);
82 	if (auto it = trackMap.find(id); it != trackMap.end())
83 		return it->second;
84 	else
85 		throw std::invalid_argument("Track ID does not exist");
86 }
87 
emplacePeerConnection(shared_ptr<PeerConnection> ptr)88 int emplacePeerConnection(shared_ptr<PeerConnection> ptr) {
89 	std::lock_guard lock(mutex);
90 	int pc = ++lastId;
91 	peerConnectionMap.emplace(std::make_pair(pc, ptr));
92 	userPointerMap.emplace(std::make_pair(pc, nullptr));
93 	return pc;
94 }
95 
emplaceDataChannel(shared_ptr<DataChannel> ptr)96 int emplaceDataChannel(shared_ptr<DataChannel> ptr) {
97 	std::lock_guard lock(mutex);
98 	int dc = ++lastId;
99 	dataChannelMap.emplace(std::make_pair(dc, ptr));
100 	userPointerMap.emplace(std::make_pair(dc, nullptr));
101 	return dc;
102 }
103 
emplaceTrack(shared_ptr<Track> ptr)104 int emplaceTrack(shared_ptr<Track> ptr) {
105 	std::lock_guard lock(mutex);
106 	int tr = ++lastId;
107 	trackMap.emplace(std::make_pair(tr, ptr));
108 	userPointerMap.emplace(std::make_pair(tr, nullptr));
109 	return tr;
110 }
111 
erasePeerConnection(int pc)112 void erasePeerConnection(int pc) {
113 	std::lock_guard lock(mutex);
114 	if (peerConnectionMap.erase(pc) == 0)
115 		throw std::invalid_argument("Peer Connection ID does not exist");
116 	userPointerMap.erase(pc);
117 }
118 
eraseDataChannel(int dc)119 void eraseDataChannel(int dc) {
120 	std::lock_guard lock(mutex);
121 	if (dataChannelMap.erase(dc) == 0)
122 		throw std::invalid_argument("Data Channel ID does not exist");
123 	userPointerMap.erase(dc);
124 }
125 
eraseTrack(int tr)126 void eraseTrack(int tr) {
127 	std::lock_guard lock(mutex);
128 	if (trackMap.erase(tr) == 0)
129 		throw std::invalid_argument("Track ID does not exist");
130 #if RTC_ENABLE_MEDIA
131 	rtcpSrReporterMap.erase(tr);
132 	rtcpChainableHandlerMap.erase(tr);
133 	rtpConfigMap.erase(tr);
134 #endif
135 	userPointerMap.erase(tr);
136 }
137 
eraseAll()138 size_t eraseAll() {
139 	std::lock_guard lock(mutex);
140 	size_t count = dataChannelMap.size() + trackMap.size() + peerConnectionMap.size();
141 	dataChannelMap.clear();
142 	trackMap.clear();
143 	peerConnectionMap.clear();
144 #if RTC_ENABLE_MEDIA
145 	count += rtcpChainableHandlerMap.size() + rtcpSrReporterMap.size() + rtpConfigMap.size();
146 	rtcpChainableHandlerMap.clear();
147 	rtcpSrReporterMap.clear();
148 	rtpConfigMap.clear();
149 #endif
150 #if RTC_ENABLE_WEBSOCKET
151 	count += webSocketMap.size() + webSocketServerMap.size();
152 	webSocketMap.clear();
153 	webSocketServerMap.clear();
154 #endif
155 	userPointerMap.clear();
156 	return count;
157 }
158 
getChannel(int id)159 shared_ptr<Channel> getChannel(int id) {
160 	std::lock_guard lock(mutex);
161 	if (auto it = dataChannelMap.find(id); it != dataChannelMap.end())
162 		return it->second;
163 	if (auto it = trackMap.find(id); it != trackMap.end())
164 		return it->second;
165 #if RTC_ENABLE_WEBSOCKET
166 	if (auto it = webSocketMap.find(id); it != webSocketMap.end())
167 		return it->second;
168 #endif
169 	throw std::invalid_argument("DataChannel, Track, or WebSocket ID does not exist");
170 }
171 
copyAndReturn(string s,char * buffer,int size)172 int copyAndReturn(string s, char *buffer, int size) {
173 	if (!buffer)
174 		return int(s.size() + 1);
175 
176 	if (size < int(s.size()))
177 		return RTC_ERR_TOO_SMALL;
178 
179 	std::copy(s.begin(), s.end(), buffer);
180 	buffer[s.size()] = '\0';
181 	return int(s.size() + 1);
182 }
183 
copyAndReturn(binary b,char * buffer,int size)184 int copyAndReturn(binary b, char *buffer, int size) {
185 	if (!buffer)
186 		return int(b.size());
187 
188 	if (size < int(b.size()))
189 		return RTC_ERR_TOO_SMALL;
190 
191 	auto data = reinterpret_cast<const char *>(b.data());
192 	std::copy(data, data + b.size(), buffer);
193 	buffer[b.size()] = '\0';
194 	return int(b.size());
195 }
196 
copyAndReturn(std::vector<T> b,T * buffer,int size)197 template <typename T> int copyAndReturn(std::vector<T> b, T *buffer, int size) {
198 	if (!buffer)
199 		return int(b.size());
200 
201 	if (size < int(b.size()))
202 		return RTC_ERR_TOO_SMALL;
203 	std::copy(b.begin(), b.end(), buffer);
204 	return int(b.size());
205 }
206 
wrap(F func)207 template <typename F> int wrap(F func) {
208 	try {
209 		return int(func());
210 
211 	} catch (const std::invalid_argument &e) {
212 		PLOG_ERROR << e.what();
213 		return RTC_ERR_INVALID;
214 	} catch (const std::exception &e) {
215 		PLOG_ERROR << e.what();
216 		return RTC_ERR_FAILURE;
217 	}
218 }
219 
220 #if RTC_ENABLE_MEDIA
221 
lowercased(string str)222 string lowercased(string str) {
223 	std::transform(str.begin(), str.end(), str.begin(),
224 	               [](unsigned char c) { return std::tolower(c); });
225 	return str;
226 }
227 
getRtcpSrReporter(int id)228 shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
229 	std::lock_guard lock(mutex);
230 	if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
231 		return it->second;
232 	} else {
233 		throw std::invalid_argument("RTCP SR reporter ID does not exist");
234 	}
235 }
236 
emplaceRtcpSrReporter(shared_ptr<RtcpSrReporter> ptr,int tr)237 void emplaceRtcpSrReporter(shared_ptr<RtcpSrReporter> ptr, int tr) {
238 	std::lock_guard lock(mutex);
239 	rtcpSrReporterMap.emplace(std::make_pair(tr, ptr));
240 }
241 
getMediaChainableHandler(int id)242 shared_ptr<MediaChainableHandler> getMediaChainableHandler(int id) {
243 	std::lock_guard lock(mutex);
244 	if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) {
245 		return it->second;
246 	} else {
247 		throw std::invalid_argument("RTCP chainable handler ID does not exist");
248 	}
249 }
250 
emplaceMediaChainableHandler(shared_ptr<MediaChainableHandler> ptr,int tr)251 void emplaceMediaChainableHandler(shared_ptr<MediaChainableHandler> ptr, int tr) {
252 	std::lock_guard lock(mutex);
253 	rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr));
254 }
255 
getRtpConfig(int id)256 shared_ptr<RtpPacketizationConfig> getRtpConfig(int id) {
257 	std::lock_guard lock(mutex);
258 	if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
259 		return it->second;
260 	} else {
261 		throw std::invalid_argument("RTP configuration ID does not exist");
262 	}
263 }
264 
emplaceRtpConfig(shared_ptr<RtpPacketizationConfig> ptr,int tr)265 void emplaceRtpConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) {
266 	std::lock_guard lock(mutex);
267 	rtpConfigMap.emplace(std::make_pair(tr, ptr));
268 }
269 
270 shared_ptr<RtpPacketizationConfig>
createRtpPacketizationConfig(const rtcPacketizationHandlerInit * init)271 createRtpPacketizationConfig(const rtcPacketizationHandlerInit *init) {
272 	if (!init)
273 		throw std::invalid_argument("Unexpected null pointer for packetization handler init");
274 
275 	if (!init->cname)
276 		throw std::invalid_argument("Unexpected null pointer for cname");
277 
278 	return std::make_shared<RtpPacketizationConfig>(init->ssrc, init->cname, init->payloadType,
279 	                                                init->clockRate, init->sequenceNumber,
280 	                                                init->timestamp);
281 }
282 
283 #endif // RTC_ENABLE_MEDIA
284 
285 #if RTC_ENABLE_WEBSOCKET
286 
getWebSocket(int id)287 shared_ptr<WebSocket> getWebSocket(int id) {
288 	std::lock_guard lock(mutex);
289 	if (auto it = webSocketMap.find(id); it != webSocketMap.end())
290 		return it->second;
291 	else
292 		throw std::invalid_argument("WebSocket ID does not exist");
293 }
294 
emplaceWebSocket(shared_ptr<WebSocket> ptr)295 int emplaceWebSocket(shared_ptr<WebSocket> ptr) {
296 	std::lock_guard lock(mutex);
297 	int ws = ++lastId;
298 	webSocketMap.emplace(std::make_pair(ws, ptr));
299 	userPointerMap.emplace(std::make_pair(ws, nullptr));
300 	return ws;
301 }
302 
eraseWebSocket(int ws)303 void eraseWebSocket(int ws) {
304 	std::lock_guard lock(mutex);
305 	if (webSocketMap.erase(ws) == 0)
306 		throw std::invalid_argument("WebSocket ID does not exist");
307 	userPointerMap.erase(ws);
308 }
309 
getWebSocketServer(int id)310 shared_ptr<WebSocketServer> getWebSocketServer(int id) {
311 	std::lock_guard lock(mutex);
312 	if (auto it = webSocketServerMap.find(id); it != webSocketServerMap.end())
313 		return it->second;
314 	else
315 		throw std::invalid_argument("WebSocketServer ID does not exist");
316 }
317 
emplaceWebSocketServer(shared_ptr<WebSocketServer> ptr)318 int emplaceWebSocketServer(shared_ptr<WebSocketServer> ptr) {
319 	std::lock_guard lock(mutex);
320 	int wsserver = ++lastId;
321 	webSocketServerMap.emplace(std::make_pair(wsserver, ptr));
322 	userPointerMap.emplace(std::make_pair(wsserver, nullptr));
323 	return wsserver;
324 }
325 
eraseWebSocketServer(int wsserver)326 void eraseWebSocketServer(int wsserver) {
327 	std::lock_guard lock(mutex);
328 	if (webSocketServerMap.erase(wsserver) == 0)
329 		throw std::invalid_argument("WebSocketServer ID does not exist");
330 	userPointerMap.erase(wsserver);
331 }
332 
333 #endif
334 
335 } // namespace
336 
rtcInitLogger(rtcLogLevel level,rtcLogCallbackFunc cb)337 void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
338 	LogCallback callback = nullptr;
339 	if (cb)
340 		callback = [cb](LogLevel level, string message) {
341 			cb(static_cast<rtcLogLevel>(level), message.c_str());
342 		};
343 
344 	InitLogger(static_cast<LogLevel>(level), callback);
345 }
346 
rtcSetUserPointer(int i,void * ptr)347 void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); }
348 
rtcGetUserPointer(int i)349 void *rtcGetUserPointer(int i) { return getUserPointer(i).value_or(nullptr); }
350 
rtcCreatePeerConnection(const rtcConfiguration * config)351 int rtcCreatePeerConnection(const rtcConfiguration *config) {
352 	return wrap([config] {
353 		Configuration c;
354 		for (int i = 0; i < config->iceServersCount; ++i)
355 			c.iceServers.emplace_back(string(config->iceServers[i]));
356 
357 		if (config->bindAddress)
358 			c.bindAddress = string(config->bindAddress);
359 
360 		if (config->portRangeBegin > 0 || config->portRangeEnd > 0) {
361 			c.portRangeBegin = config->portRangeBegin;
362 			c.portRangeEnd = config->portRangeEnd;
363 		}
364 
365 		c.certificateType = static_cast<CertificateType>(config->certificateType);
366 		c.iceTransportPolicy = static_cast<TransportPolicy>(config->iceTransportPolicy);
367 		c.enableIceTcp = config->enableIceTcp;
368 		c.disableAutoNegotiation = config->disableAutoNegotiation;
369 
370 		if (config->mtu > 0)
371 			c.mtu = size_t(config->mtu);
372 
373 		if (config->maxMessageSize)
374 			c.maxMessageSize = size_t(config->maxMessageSize);
375 
376 		return emplacePeerConnection(std::make_shared<PeerConnection>(std::move(c)));
377 	});
378 }
379 
rtcDeletePeerConnection(int pc)380 int rtcDeletePeerConnection(int pc) {
381 	return wrap([pc] {
382 		auto peerConnection = getPeerConnection(pc);
383 		peerConnection->onDataChannel(nullptr);
384 		peerConnection->onTrack(nullptr);
385 		peerConnection->onLocalDescription(nullptr);
386 		peerConnection->onLocalCandidate(nullptr);
387 		peerConnection->onStateChange(nullptr);
388 		peerConnection->onGatheringStateChange(nullptr);
389 
390 		erasePeerConnection(pc);
391 		return RTC_ERR_SUCCESS;
392 	});
393 }
394 
rtcSetLocalDescriptionCallback(int pc,rtcDescriptionCallbackFunc cb)395 int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
396 	return wrap([&] {
397 		auto peerConnection = getPeerConnection(pc);
398 		if (cb)
399 			peerConnection->onLocalDescription([pc, cb](Description desc) {
400 				if (auto ptr = getUserPointer(pc))
401 					cb(pc, string(desc).c_str(), desc.typeString().c_str(), *ptr);
402 			});
403 		else
404 			peerConnection->onLocalDescription(nullptr);
405 		return RTC_ERR_SUCCESS;
406 	});
407 }
408 
rtcSetLocalCandidateCallback(int pc,rtcCandidateCallbackFunc cb)409 int rtcSetLocalCandidateCallback(int pc, rtcCandidateCallbackFunc cb) {
410 	return wrap([&] {
411 		auto peerConnection = getPeerConnection(pc);
412 		if (cb)
413 			peerConnection->onLocalCandidate([pc, cb](Candidate cand) {
414 				if (auto ptr = getUserPointer(pc))
415 					cb(pc, cand.candidate().c_str(), cand.mid().c_str(), *ptr);
416 			});
417 		else
418 			peerConnection->onLocalCandidate(nullptr);
419 		return RTC_ERR_SUCCESS;
420 	});
421 }
422 
rtcSetStateChangeCallback(int pc,rtcStateChangeCallbackFunc cb)423 int rtcSetStateChangeCallback(int pc, rtcStateChangeCallbackFunc cb) {
424 	return wrap([&] {
425 		auto peerConnection = getPeerConnection(pc);
426 		if (cb)
427 			peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
428 				if (auto ptr = getUserPointer(pc))
429 					cb(pc, static_cast<rtcState>(state), *ptr);
430 			});
431 		else
432 			peerConnection->onStateChange(nullptr);
433 		return RTC_ERR_SUCCESS;
434 	});
435 }
436 
rtcSetGatheringStateChangeCallback(int pc,rtcGatheringStateCallbackFunc cb)437 int rtcSetGatheringStateChangeCallback(int pc, rtcGatheringStateCallbackFunc cb) {
438 	return wrap([&] {
439 		auto peerConnection = getPeerConnection(pc);
440 		if (cb)
441 			peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
442 				if (auto ptr = getUserPointer(pc))
443 					cb(pc, static_cast<rtcGatheringState>(state), *ptr);
444 			});
445 		else
446 			peerConnection->onGatheringStateChange(nullptr);
447 		return RTC_ERR_SUCCESS;
448 	});
449 }
450 
rtcSetSignalingStateChangeCallback(int pc,rtcSignalingStateCallbackFunc cb)451 int rtcSetSignalingStateChangeCallback(int pc, rtcSignalingStateCallbackFunc cb) {
452 	return wrap([&] {
453 		auto peerConnection = getPeerConnection(pc);
454 		if (cb)
455 			peerConnection->onSignalingStateChange([pc, cb](PeerConnection::SignalingState state) {
456 				if (auto ptr = getUserPointer(pc))
457 					cb(pc, static_cast<rtcSignalingState>(state), *ptr);
458 			});
459 		else
460 			peerConnection->onGatheringStateChange(nullptr);
461 		return RTC_ERR_SUCCESS;
462 	});
463 }
464 
rtcSetDataChannelCallback(int pc,rtcDataChannelCallbackFunc cb)465 int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb) {
466 	return wrap([&] {
467 		auto peerConnection = getPeerConnection(pc);
468 		if (cb)
469 			peerConnection->onDataChannel([pc, cb](shared_ptr<DataChannel> dataChannel) {
470 				int dc = emplaceDataChannel(dataChannel);
471 				if (auto ptr = getUserPointer(pc)) {
472 					rtcSetUserPointer(dc, *ptr);
473 					cb(pc, dc, *ptr);
474 				}
475 			});
476 		else
477 			peerConnection->onDataChannel(nullptr);
478 		return RTC_ERR_SUCCESS;
479 	});
480 }
481 
rtcSetTrackCallback(int pc,rtcTrackCallbackFunc cb)482 int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb) {
483 	return wrap([&] {
484 		auto peerConnection = getPeerConnection(pc);
485 		if (cb)
486 			peerConnection->onTrack([pc, cb](shared_ptr<Track> track) {
487 				int tr = emplaceTrack(track);
488 				if (auto ptr = getUserPointer(pc)) {
489 					rtcSetUserPointer(tr, *ptr);
490 					cb(pc, tr, *ptr);
491 				}
492 			});
493 		else
494 			peerConnection->onTrack(nullptr);
495 		return RTC_ERR_SUCCESS;
496 	});
497 }
498 
rtcSetLocalDescription(int pc,const char * type)499 int rtcSetLocalDescription(int pc, const char *type) {
500 	return wrap([&] {
501 		auto peerConnection = getPeerConnection(pc);
502 		peerConnection->setLocalDescription(type ? Description::stringToType(type)
503 		                                         : Description::Type::Unspec);
504 		return RTC_ERR_SUCCESS;
505 	});
506 }
507 
rtcSetRemoteDescription(int pc,const char * sdp,const char * type)508 int rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
509 	return wrap([&] {
510 		auto peerConnection = getPeerConnection(pc);
511 
512 		if (!sdp)
513 			throw std::invalid_argument("Unexpected null pointer for remote description");
514 
515 		peerConnection->setRemoteDescription({string(sdp), type ? string(type) : ""});
516 		return RTC_ERR_SUCCESS;
517 	});
518 }
519 
rtcAddRemoteCandidate(int pc,const char * cand,const char * mid)520 int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid) {
521 	return wrap([&] {
522 		auto peerConnection = getPeerConnection(pc);
523 
524 		if (!cand)
525 			throw std::invalid_argument("Unexpected null pointer for remote candidate");
526 
527 		peerConnection->addRemoteCandidate({string(cand), mid ? string(mid) : ""});
528 		return RTC_ERR_SUCCESS;
529 	});
530 }
531 
rtcGetLocalDescription(int pc,char * buffer,int size)532 int rtcGetLocalDescription(int pc, char *buffer, int size) {
533 	return wrap([&] {
534 		auto peerConnection = getPeerConnection(pc);
535 
536 		if (auto desc = peerConnection->localDescription())
537 			return copyAndReturn(string(*desc), buffer, size);
538 		else
539 			return RTC_ERR_NOT_AVAIL;
540 	});
541 }
542 
rtcGetRemoteDescription(int pc,char * buffer,int size)543 int rtcGetRemoteDescription(int pc, char *buffer, int size) {
544 	return wrap([&] {
545 		auto peerConnection = getPeerConnection(pc);
546 
547 		if (auto desc = peerConnection->remoteDescription())
548 			return copyAndReturn(string(*desc), buffer, size);
549 		else
550 			return RTC_ERR_NOT_AVAIL;
551 	});
552 }
553 
rtcGetLocalDescriptionType(int pc,char * buffer,int size)554 int rtcGetLocalDescriptionType(int pc, char *buffer, int size) {
555 	return wrap([&] {
556 		auto peerConnection = getPeerConnection(pc);
557 
558 		if (auto desc = peerConnection->localDescription())
559 			return copyAndReturn(desc->typeString(), buffer, size);
560 		else
561 			return RTC_ERR_NOT_AVAIL;
562 	});
563 }
564 
rtcGetRemoteDescriptionType(int pc,char * buffer,int size)565 int rtcGetRemoteDescriptionType(int pc, char *buffer, int size) {
566 	return wrap([&] {
567 		auto peerConnection = getPeerConnection(pc);
568 
569 		if (auto desc = peerConnection->remoteDescription())
570 			return copyAndReturn(desc->typeString(), buffer, size);
571 		else
572 			return RTC_ERR_NOT_AVAIL;
573 	});
574 }
575 
rtcGetLocalAddress(int pc,char * buffer,int size)576 int rtcGetLocalAddress(int pc, char *buffer, int size) {
577 	return wrap([&] {
578 		auto peerConnection = getPeerConnection(pc);
579 
580 		if (auto addr = peerConnection->localAddress())
581 			return copyAndReturn(std::move(*addr), buffer, size);
582 		else
583 			return RTC_ERR_NOT_AVAIL;
584 	});
585 }
586 
rtcGetRemoteAddress(int pc,char * buffer,int size)587 int rtcGetRemoteAddress(int pc, char *buffer, int size) {
588 	return wrap([&] {
589 		auto peerConnection = getPeerConnection(pc);
590 
591 		if (auto addr = peerConnection->remoteAddress())
592 			return copyAndReturn(std::move(*addr), buffer, size);
593 		else
594 			return RTC_ERR_NOT_AVAIL;
595 	});
596 }
597 
rtcGetSelectedCandidatePair(int pc,char * local,int localSize,char * remote,int remoteSize)598 int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, char *remote, int remoteSize) {
599 	return wrap([&] {
600 		auto peerConnection = getPeerConnection(pc);
601 
602 		Candidate localCand;
603 		Candidate remoteCand;
604 		if (!peerConnection->getSelectedCandidatePair(&localCand, &remoteCand))
605 			return RTC_ERR_NOT_AVAIL;
606 
607 		int localRet = copyAndReturn(string(localCand), local, localSize);
608 		if (localRet < 0)
609 			return localRet;
610 
611 		int remoteRet = copyAndReturn(string(remoteCand), remote, remoteSize);
612 		if (remoteRet < 0)
613 			return remoteRet;
614 
615 		return std::max(localRet, remoteRet);
616 	});
617 }
618 
rtcSetOpenCallback(int id,rtcOpenCallbackFunc cb)619 int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb) {
620 	return wrap([&] {
621 		auto channel = getChannel(id);
622 		if (cb)
623 			channel->onOpen([id, cb]() {
624 				if (auto ptr = getUserPointer(id))
625 					cb(id, *ptr);
626 			});
627 		else
628 			channel->onOpen(nullptr);
629 		return RTC_ERR_SUCCESS;
630 	});
631 }
632 
rtcSetClosedCallback(int id,rtcClosedCallbackFunc cb)633 int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb) {
634 	return wrap([&] {
635 		auto channel = getChannel(id);
636 		if (cb)
637 			channel->onClosed([id, cb]() {
638 				if (auto ptr = getUserPointer(id))
639 					cb(id, *ptr);
640 			});
641 		else
642 			channel->onClosed(nullptr);
643 		return RTC_ERR_SUCCESS;
644 	});
645 }
646 
rtcSetErrorCallback(int id,rtcErrorCallbackFunc cb)647 int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb) {
648 	return wrap([&] {
649 		auto channel = getChannel(id);
650 		if (cb)
651 			channel->onError([id, cb](string error) {
652 				if (auto ptr = getUserPointer(id))
653 					cb(id, error.c_str(), *ptr);
654 			});
655 		else
656 			channel->onError(nullptr);
657 		return RTC_ERR_SUCCESS;
658 	});
659 }
660 
rtcSetMessageCallback(int id,rtcMessageCallbackFunc cb)661 int rtcSetMessageCallback(int id, rtcMessageCallbackFunc cb) {
662 	return wrap([&] {
663 		auto channel = getChannel(id);
664 		if (cb)
665 			channel->onMessage(
666 			    [id, cb](binary b) {
667 				    if (auto ptr = getUserPointer(id))
668 					    cb(id, reinterpret_cast<const char *>(b.data()), int(b.size()), *ptr);
669 			    },
670 			    [id, cb](string s) {
671 				    if (auto ptr = getUserPointer(id))
672 					    cb(id, s.c_str(), -int(s.size() + 1), *ptr);
673 			    });
674 		else
675 			channel->onMessage(nullptr);
676 		return RTC_ERR_SUCCESS;
677 	});
678 }
679 
rtcSendMessage(int id,const char * data,int size)680 int rtcSendMessage(int id, const char *data, int size) {
681 	return wrap([&] {
682 		auto channel = getChannel(id);
683 
684 		if (!data && size != 0)
685 			throw std::invalid_argument("Unexpected null pointer for data");
686 
687 		if (size >= 0) {
688 			auto b = reinterpret_cast<const byte *>(data);
689 			channel->send(binary(b, b + size));
690 			return size;
691 		} else {
692 			string str(data);
693 			int len = int(str.size());
694 			channel->send(std::move(str));
695 			return len;
696 		}
697 	});
698 }
699 
rtcIsOpen(int id)700 bool rtcIsOpen(int id) {
701 	return wrap([id] { return getChannel(id)->isOpen() ? 0 : 1; }) == 0 ? true : false;
702 }
703 
rtcIsClosed(int id)704 bool rtcIsClosed(int id) {
705 	return wrap([id] { return getChannel(id)->isClosed() ? 0 : 1; }) == 0 ? true : false;
706 }
707 
rtcGetBufferedAmount(int id)708 int rtcGetBufferedAmount(int id) {
709 	return wrap([id] {
710 		auto channel = getChannel(id);
711 		return int(channel->bufferedAmount());
712 	});
713 }
714 
rtcSetBufferedAmountLowThreshold(int id,int amount)715 int rtcSetBufferedAmountLowThreshold(int id, int amount) {
716 	return wrap([&] {
717 		auto channel = getChannel(id);
718 		channel->setBufferedAmountLowThreshold(size_t(amount));
719 		return RTC_ERR_SUCCESS;
720 	});
721 }
722 
rtcSetBufferedAmountLowCallback(int id,rtcBufferedAmountLowCallbackFunc cb)723 int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb) {
724 	return wrap([&] {
725 		auto channel = getChannel(id);
726 		if (cb)
727 			channel->onBufferedAmountLow([id, cb]() {
728 				if (auto ptr = getUserPointer(id))
729 					cb(id, *ptr);
730 			});
731 		else
732 			channel->onBufferedAmountLow(nullptr);
733 		return RTC_ERR_SUCCESS;
734 	});
735 }
736 
rtcGetAvailableAmount(int id)737 int rtcGetAvailableAmount(int id) {
738 	return wrap([id] { return int(getChannel(id)->availableAmount()); });
739 }
740 
rtcSetAvailableCallback(int id,rtcAvailableCallbackFunc cb)741 int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb) {
742 	return wrap([&] {
743 		auto channel = getChannel(id);
744 		if (cb)
745 			channel->onAvailable([id, cb]() {
746 				if (auto ptr = getUserPointer(id))
747 					cb(id, *ptr);
748 			});
749 		else
750 			channel->onAvailable(nullptr);
751 		return RTC_ERR_SUCCESS;
752 	});
753 }
754 
rtcReceiveMessage(int id,char * buffer,int * size)755 int rtcReceiveMessage(int id, char *buffer, int *size) {
756 	return wrap([&] {
757 		auto channel = getChannel(id);
758 
759 		if (!size)
760 			throw std::invalid_argument("Unexpected null pointer for size");
761 
762 		*size = std::abs(*size);
763 
764 		auto message = channel->peek();
765 		if (!message)
766 			return RTC_ERR_NOT_AVAIL;
767 
768 		return std::visit( //
769 		    overloaded{
770 		        [&](binary b) {
771 			        int ret = copyAndReturn(std::move(b), buffer, *size);
772 			        if (ret >= 0) {
773 				        channel->receive(); // discard
774 				        *size = ret;
775 				        return RTC_ERR_SUCCESS;
776 			        } else {
777 				        *size = int(b.size());
778 				        return ret;
779 			        }
780 		        },
781 		        [&](string s) {
782 			        int ret = copyAndReturn(std::move(s), buffer, *size);
783 			        if (ret >= 0) {
784 				        channel->receive(); // discard
785 				        *size = -ret;
786 				        return RTC_ERR_SUCCESS;
787 			        } else {
788 				        *size = -int(s.size() + 1);
789 				        return ret;
790 			        }
791 		        },
792 		    },
793 		    *message);
794 	});
795 }
796 
rtcCreateDataChannel(int pc,const char * label)797 int rtcCreateDataChannel(int pc, const char *label) {
798 	return rtcCreateDataChannelEx(pc, label, nullptr);
799 }
800 
rtcCreateDataChannelEx(int pc,const char * label,const rtcDataChannelInit * init)801 int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *init) {
802 	return wrap([&] {
803 		DataChannelInit dci = {};
804 		if (init) {
805 			auto *reliability = &init->reliability;
806 			dci.reliability.unordered = reliability->unordered;
807 			if (reliability->unreliable) {
808 				if (reliability->maxPacketLifeTime > 0) {
809 					dci.reliability.type = Reliability::Type::Timed;
810 					dci.reliability.rexmit = milliseconds(reliability->maxPacketLifeTime);
811 				} else {
812 					dci.reliability.type = Reliability::Type::Rexmit;
813 					dci.reliability.rexmit = reliability->maxRetransmits;
814 				}
815 			} else {
816 				dci.reliability.type = Reliability::Type::Reliable;
817 			}
818 
819 			dci.negotiated = init->negotiated;
820 			dci.id = init->manualStream ? std::make_optional(init->stream) : nullopt;
821 			dci.protocol = init->protocol ? init->protocol : "";
822 		}
823 
824 		auto peerConnection = getPeerConnection(pc);
825 		int dc = emplaceDataChannel(
826 		    peerConnection->createDataChannel(string(label ? label : ""), std::move(dci)));
827 
828 		if (auto ptr = getUserPointer(pc))
829 			rtcSetUserPointer(dc, *ptr);
830 
831 		return dc;
832 	});
833 }
834 
rtcDeleteDataChannel(int dc)835 int rtcDeleteDataChannel(int dc) {
836 	return wrap([dc] {
837 		auto dataChannel = getDataChannel(dc);
838 		dataChannel->onOpen(nullptr);
839 		dataChannel->onClosed(nullptr);
840 		dataChannel->onError(nullptr);
841 		dataChannel->onMessage(nullptr);
842 		dataChannel->onBufferedAmountLow(nullptr);
843 		dataChannel->onAvailable(nullptr);
844 
845 		eraseDataChannel(dc);
846 		return RTC_ERR_SUCCESS;
847 	});
848 }
849 
rtcGetDataChannelStream(int dc)850 int rtcGetDataChannelStream(int dc) {
851 	return wrap([dc] {
852 		auto dataChannel = getDataChannel(dc);
853 		return int(dataChannel->id());
854 	});
855 }
856 
rtcGetDataChannelLabel(int dc,char * buffer,int size)857 int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
858 	return wrap([&] {
859 		auto dataChannel = getDataChannel(dc);
860 		return copyAndReturn(dataChannel->label(), buffer, size);
861 	});
862 }
863 
rtcGetDataChannelProtocol(int dc,char * buffer,int size)864 int rtcGetDataChannelProtocol(int dc, char *buffer, int size) {
865 	return wrap([&] {
866 		auto dataChannel = getDataChannel(dc);
867 		return copyAndReturn(dataChannel->protocol(), buffer, size);
868 	});
869 }
870 
rtcGetDataChannelReliability(int dc,rtcReliability * reliability)871 int rtcGetDataChannelReliability(int dc, rtcReliability *reliability) {
872 	return wrap([&] {
873 		auto dataChannel = getDataChannel(dc);
874 
875 		if (!reliability)
876 			throw std::invalid_argument("Unexpected null pointer for reliability");
877 
878 		Reliability dcr = dataChannel->reliability();
879 		std::memset(reliability, 0, sizeof(*reliability));
880 		reliability->unordered = dcr.unordered;
881 		if (dcr.type == Reliability::Type::Timed) {
882 			reliability->unreliable = true;
883 			reliability->maxPacketLifeTime = int(std::get<milliseconds>(dcr.rexmit).count());
884 		} else if (dcr.type == Reliability::Type::Rexmit) {
885 			reliability->unreliable = true;
886 			reliability->maxRetransmits = std::get<int>(dcr.rexmit);
887 		} else {
888 			reliability->unreliable = false;
889 		}
890 		return RTC_ERR_SUCCESS;
891 	});
892 }
893 
rtcAddTrack(int pc,const char * mediaDescriptionSdp)894 int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
895 	return wrap([&] {
896 		if (!mediaDescriptionSdp)
897 			throw std::invalid_argument("Unexpected null pointer for track media description");
898 
899 		auto peerConnection = getPeerConnection(pc);
900 		Description::Media media{string(mediaDescriptionSdp)};
901 		int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
902 		if (auto ptr = getUserPointer(pc))
903 			rtcSetUserPointer(tr, *ptr);
904 
905 		return tr;
906 	});
907 }
908 
rtcAddTrackEx(int pc,const rtcTrackInit * init)909 int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
910 	return wrap([&] {
911 		auto peerConnection = getPeerConnection(pc);
912 
913 		if (!init)
914 			throw std::invalid_argument("Unexpected null pointer for track init");
915 
916 		auto direction = static_cast<Description::Direction>(init->direction);
917 
918 		string mid;
919 		if (init->mid) {
920 			mid = string(init->mid);
921 		} else {
922 			switch (init->codec) {
923 			case RTC_CODEC_H264:
924 			case RTC_CODEC_VP8:
925 			case RTC_CODEC_VP9:
926 				mid = "video";
927 				break;
928 			case RTC_CODEC_OPUS:
929 				mid = "audio";
930 				break;
931 			default:
932 				mid = "video";
933 				break;
934 			}
935 		}
936 
937 		optional<Description::Media> optDescription = nullopt;
938 
939 		switch (init->codec) {
940 		case RTC_CODEC_H264:
941 		case RTC_CODEC_VP8:
942 		case RTC_CODEC_VP9: {
943 			auto desc = Description::Video(mid, direction);
944 			switch (init->codec) {
945 			case RTC_CODEC_H264:
946 				desc.addH264Codec(init->payloadType);
947 				break;
948 			case RTC_CODEC_VP8:
949 				desc.addVP8Codec(init->payloadType);
950 				break;
951 			case RTC_CODEC_VP9:
952 				desc.addVP8Codec(init->payloadType);
953 				break;
954 			default:
955 				break;
956 			}
957 			optDescription = desc;
958 			break;
959 		}
960 		case RTC_CODEC_OPUS: {
961 			auto desc = Description::Audio(mid, direction);
962 			switch (init->codec) {
963 			case RTC_CODEC_OPUS:
964 				desc.addOpusCodec(init->payloadType);
965 				break;
966 			default:
967 				break;
968 			}
969 			optDescription = desc;
970 			break;
971 		}
972 		default:
973 			break;
974 		}
975 
976 		if (!optDescription)
977 			throw std::invalid_argument("Unexpected codec");
978 
979 		auto desc = std::move(*optDescription);
980 		desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
981 		             init->msid ? std::make_optional(string(init->msid)) : nullopt,
982 		             init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
983 
984 		int tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
985 
986 		if (auto ptr = getUserPointer(pc))
987 			rtcSetUserPointer(tr, *ptr);
988 
989 		return tr;
990 	});
991 }
992 
rtcDeleteTrack(int tr)993 int rtcDeleteTrack(int tr) {
994 	return wrap([&] {
995 		auto track = getTrack(tr);
996 		track->onOpen(nullptr);
997 		track->onClosed(nullptr);
998 		track->onError(nullptr);
999 		track->onMessage(nullptr);
1000 		track->onBufferedAmountLow(nullptr);
1001 		track->onAvailable(nullptr);
1002 
1003 		eraseTrack(tr);
1004 		return RTC_ERR_SUCCESS;
1005 	});
1006 }
1007 
rtcGetTrackDescription(int tr,char * buffer,int size)1008 int rtcGetTrackDescription(int tr, char *buffer, int size) {
1009 	return wrap([&] {
1010 		auto track = getTrack(tr);
1011 		return copyAndReturn(track->description(), buffer, size);
1012 	});
1013 }
1014 
1015 #if RTC_ENABLE_MEDIA
1016 
setSSRC(Description::Media * description,uint32_t ssrc,const char * _name,const char * _msid,const char * _trackID)1017 void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid,
1018              const char *_trackID) {
1019 
1020 	optional<string> name = nullopt;
1021 	if (_name) {
1022 		name = string(_name);
1023 	}
1024 
1025 	optional<string> msid = nullopt;
1026 	if (_msid) {
1027 		msid = string(_msid);
1028 	}
1029 
1030 	optional<string> trackID = nullopt;
1031 	if (_trackID) {
1032 		trackID = string(_trackID);
1033 	}
1034 
1035 	description->addSSRC(ssrc, name, msid, trackID);
1036 }
1037 
rtcSetH264PacketizationHandler(int tr,const rtcPacketizationHandlerInit * init)1038 int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
1039 	return wrap([&] {
1040 		auto track = getTrack(tr);
1041 		// create RTP configuration
1042 		auto rtpConfig = createRtpPacketizationConfig(init);
1043 		// create packetizer
1044 		auto nalSeparator = init ? init->nalSeparator : RTC_NAL_SEPARATOR_LENGTH;
1045 		auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize
1046 		                                                     : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE;
1047 		auto packetizer = std::make_shared<H264RtpPacketizer>(
1048 		    static_cast<rtc::H264RtpPacketizer::Separator>(nalSeparator), rtpConfig,
1049 		    maxFragmentSize);
1050 		// create H264 handler
1051 		auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
1052 		emplaceMediaChainableHandler(h264Handler, tr);
1053 		emplaceRtpConfig(rtpConfig, tr);
1054 		// set handler
1055 		track->setMediaHandler(h264Handler);
1056 		return RTC_ERR_SUCCESS;
1057 	});
1058 }
1059 
rtcSetOpusPacketizationHandler(int tr,const rtcPacketizationHandlerInit * init)1060 int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
1061 	return wrap([&] {
1062 		auto track = getTrack(tr);
1063 		// create RTP configuration
1064 		auto rtpConfig = createRtpPacketizationConfig(init);
1065 		// create packetizer
1066 		auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
1067 		// create Opus handler
1068 		auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
1069 		emplaceMediaChainableHandler(opusHandler, tr);
1070 		emplaceRtpConfig(rtpConfig, tr);
1071 		// set handler
1072 		track->setMediaHandler(opusHandler);
1073 		return RTC_ERR_SUCCESS;
1074 	});
1075 }
1076 
rtcChainRtcpSrReporter(int tr)1077 int rtcChainRtcpSrReporter(int tr) {
1078 	return wrap([tr] {
1079 		auto config = getRtpConfig(tr);
1080 		auto reporter = std::make_shared<RtcpSrReporter>(config);
1081 		emplaceRtcpSrReporter(reporter, tr);
1082 		auto chainableHandler = getMediaChainableHandler(tr);
1083 		chainableHandler->addToChain(reporter);
1084 		return RTC_ERR_SUCCESS;
1085 	});
1086 }
1087 
rtcChainRtcpNackResponder(int tr,unsigned int maxStoredPacketsCount)1088 int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
1089 	return wrap([tr, maxStoredPacketsCount] {
1090 		auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
1091 		auto chainableHandler = getMediaChainableHandler(tr);
1092 		chainableHandler->addToChain(responder);
1093 		return RTC_ERR_SUCCESS;
1094 	});
1095 }
1096 
rtcSetRtpConfigurationStartTime(int id,const rtcStartTime * startTime)1097 int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime) {
1098 	return wrap([&] {
1099 		auto config = getRtpConfig(id);
1100 		auto epoch = startTime->since1970 ? RtpPacketizationConfig::EpochStart::T1970
1101 		                                  : RtpPacketizationConfig::EpochStart::T1900;
1102 		config->setStartTime(startTime->seconds, epoch, startTime->timestamp);
1103 		return RTC_ERR_SUCCESS;
1104 	});
1105 }
1106 
rtcStartRtcpSenderReporterRecording(int id)1107 int rtcStartRtcpSenderReporterRecording(int id) {
1108 	return wrap([id] {
1109 		auto sender = getRtcpSrReporter(id);
1110 		sender->startRecording();
1111 		return RTC_ERR_SUCCESS;
1112 	});
1113 }
1114 
rtcTransformSecondsToTimestamp(int id,double seconds,uint32_t * timestamp)1115 int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
1116 	return wrap([&] {
1117 		auto config = getRtpConfig(id);
1118 		*timestamp = config->secondsToTimestamp(seconds);
1119 		return RTC_ERR_SUCCESS;
1120 	});
1121 }
1122 
rtcTransformTimestampToSeconds(int id,uint32_t timestamp,double * seconds)1123 int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
1124 	return wrap([&] {
1125 		auto config = getRtpConfig(id);
1126 		*seconds = config->timestampToSeconds(timestamp);
1127 		return RTC_ERR_SUCCESS;
1128 	});
1129 }
1130 
rtcGetCurrentTrackTimestamp(int id,uint32_t * timestamp)1131 int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
1132 	return wrap([&] {
1133 		auto config = getRtpConfig(id);
1134 		*timestamp = config->timestamp;
1135 		return RTC_ERR_SUCCESS;
1136 	});
1137 }
1138 
rtcGetTrackStartTimestamp(int id,uint32_t * timestamp)1139 int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
1140 	return wrap([&] {
1141 		auto config = getRtpConfig(id);
1142 		*timestamp = config->startTimestamp;
1143 		return RTC_ERR_SUCCESS;
1144 	});
1145 }
1146 
rtcSetTrackRtpTimestamp(int id,uint32_t timestamp)1147 int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) {
1148 	return wrap([&] {
1149 		auto config = getRtpConfig(id);
1150 		config->timestamp = timestamp;
1151 		return RTC_ERR_SUCCESS;
1152 	});
1153 }
1154 
rtcGetPreviousTrackSenderReportTimestamp(int id,uint32_t * timestamp)1155 int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
1156 	return wrap([&] {
1157 		auto sender = getRtcpSrReporter(id);
1158 		*timestamp = sender->previousReportedTimestamp;
1159 		return RTC_ERR_SUCCESS;
1160 	});
1161 }
1162 
rtcSetNeedsToSendRtcpSr(int id)1163 int rtcSetNeedsToSendRtcpSr(int id) {
1164 	return wrap([id] {
1165 		auto sender = getRtcpSrReporter(id);
1166 		sender->setNeedsToReport();
1167 		return RTC_ERR_SUCCESS;
1168 	});
1169 }
1170 
rtcGetTrackPayloadTypesForCodec(int tr,const char * ccodec,int * buffer,int size)1171 int rtcGetTrackPayloadTypesForCodec(int tr, const char *ccodec, int *buffer, int size) {
1172 	return wrap([&] {
1173 		auto track = getTrack(tr);
1174 		auto codec = lowercased(string(ccodec));
1175 		auto description = track->description();
1176 		std::vector<int> payloadTypes{};
1177 		payloadTypes.reserve(std::max(size, 0));
1178 		for (auto it = description.beginMaps(); it != description.endMaps(); it++) {
1179 			auto element = *it;
1180 			if (lowercased(element.second.format) == codec) {
1181 				payloadTypes.push_back(element.first);
1182 			}
1183 		}
1184 		return copyAndReturn(payloadTypes, buffer, size);
1185 	});
1186 }
1187 
rtcGetSsrcsForTrack(int tr,uint32_t * buffer,int count)1188 int rtcGetSsrcsForTrack(int tr, uint32_t *buffer, int count) {
1189 	return wrap([&] {
1190 		auto track = getTrack(tr);
1191 		auto ssrcs = track->description().getSSRCs();
1192 		return copyAndReturn(ssrcs, buffer, count);
1193 	});
1194 }
1195 
rtcGetCNameForSsrc(int tr,uint32_t ssrc,char * cname,int cnameSize)1196 int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char *cname, int cnameSize) {
1197 	return wrap([&] {
1198 		auto track = getTrack(tr);
1199 		auto description = track->description();
1200 		auto optCName = description.getCNameForSsrc(ssrc);
1201 		if (optCName.has_value()) {
1202 			return copyAndReturn(optCName.value(), cname, cnameSize);
1203 		} else {
1204 			return 0;
1205 		}
1206 	});
1207 }
1208 
rtcGetSsrcsForType(const char * mediaType,const char * sdp,uint32_t * buffer,int bufferSize)1209 int rtcGetSsrcsForType(const char *mediaType, const char *sdp, uint32_t *buffer, int bufferSize) {
1210 	return wrap([&] {
1211 		auto type = lowercased(string(mediaType));
1212 		auto oldSDP = string(sdp);
1213 		auto description = Description(oldSDP, "unspec");
1214 		auto mediaCount = description.mediaCount();
1215 		for (unsigned int i = 0; i < mediaCount; i++) {
1216 			if (std::holds_alternative<Description::Media *>(description.media(i))) {
1217 				auto media = std::get<Description::Media *>(description.media(i));
1218 				auto currentMediaType = lowercased(media->type());
1219 				if (currentMediaType == type) {
1220 					auto ssrcs = media->getSSRCs();
1221 					return copyAndReturn(ssrcs, buffer, bufferSize);
1222 				}
1223 			}
1224 		}
1225 		return 0;
1226 	});
1227 }
1228 
rtcSetSsrcForType(const char * mediaType,const char * sdp,char * buffer,const int bufferSize,rtcSsrcForTypeInit * init)1229 int rtcSetSsrcForType(const char *mediaType, const char *sdp, char *buffer, const int bufferSize,
1230                       rtcSsrcForTypeInit *init) {
1231 	return wrap([&] {
1232 		auto type = lowercased(string(mediaType));
1233 		auto prevSDP = string(sdp);
1234 		auto description = Description(prevSDP, "unspec");
1235 		auto mediaCount = description.mediaCount();
1236 		for (unsigned int i = 0; i < mediaCount; i++) {
1237 			if (std::holds_alternative<Description::Media *>(description.media(i))) {
1238 				auto media = std::get<Description::Media *>(description.media(i));
1239 				auto currentMediaType = lowercased(media->type());
1240 				if (currentMediaType == type) {
1241 					setSSRC(media, init->ssrc, init->name, init->msid, init->trackId);
1242 					break;
1243 				}
1244 			}
1245 		}
1246 		return copyAndReturn(string(description), buffer, bufferSize);
1247 	});
1248 }
1249 
1250 #endif // RTC_ENABLE_MEDIA
1251 
1252 #if RTC_ENABLE_WEBSOCKET
1253 
rtcCreateWebSocket(const char * url)1254 int rtcCreateWebSocket(const char *url) {
1255 	return wrap([&] {
1256 		auto webSocket = std::make_shared<WebSocket>();
1257 		webSocket->open(url);
1258 		return emplaceWebSocket(webSocket);
1259 	});
1260 }
1261 
rtcCreateWebSocketEx(const char * url,const rtcWsConfiguration * config)1262 int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config) {
1263 	return wrap([&] {
1264 		if (!url)
1265 			throw std::invalid_argument("Unexpected null pointer for URL");
1266 
1267 		if (!config)
1268 			throw std::invalid_argument("Unexpected null pointer for config");
1269 
1270 		WebSocket::Configuration c;
1271 		c.disableTlsVerification = config->disableTlsVerification;
1272 		auto webSocket = std::make_shared<WebSocket>(std::move(c));
1273 		webSocket->open(url);
1274 		return emplaceWebSocket(webSocket);
1275 	});
1276 }
1277 
rtcDeleteWebSocket(int ws)1278 int rtcDeleteWebSocket(int ws) {
1279 	return wrap([&] {
1280 		auto webSocket = getWebSocket(ws);
1281 		webSocket->onOpen(nullptr);
1282 		webSocket->onClosed(nullptr);
1283 		webSocket->onError(nullptr);
1284 		webSocket->onMessage(nullptr);
1285 		webSocket->onBufferedAmountLow(nullptr);
1286 		webSocket->onAvailable(nullptr);
1287 
1288 		eraseWebSocket(ws);
1289 		return RTC_ERR_SUCCESS;
1290 	});
1291 }
1292 
rtcGetWebSocketRemoteAddress(int ws,char * buffer,int size)1293 int rtcGetWebSocketRemoteAddress(int ws, char *buffer, int size) {
1294 	return wrap([&] {
1295 		auto webSocket = getWebSocket(ws);
1296 		if (auto remoteAddress = webSocket->remoteAddress())
1297 			return copyAndReturn(*remoteAddress, buffer, size);
1298 		else
1299 			return RTC_ERR_NOT_AVAIL;
1300 	});
1301 }
1302 
rtcGetWebSocketPath(int ws,char * buffer,int size)1303 int rtcGetWebSocketPath(int ws, char *buffer, int size) {
1304 	return wrap([&] {
1305 		auto webSocket = getWebSocket(ws);
1306 		if (auto path = webSocket->path())
1307 			return copyAndReturn(*path, buffer, size);
1308 		else
1309 			return RTC_ERR_NOT_AVAIL;
1310 	});
1311 }
1312 
rtcCreateWebSocketServer(const rtcWsServerConfiguration * config,rtcWebSocketClientCallbackFunc cb)1313 RTC_EXPORT int rtcCreateWebSocketServer(const rtcWsServerConfiguration *config,
1314                                         rtcWebSocketClientCallbackFunc cb) {
1315 	return wrap([&] {
1316 		if (!config)
1317 			throw std::invalid_argument("Unexpected null pointer for config");
1318 
1319 		if (!cb)
1320 			throw std::invalid_argument("Unexpected null pointer for client callback");
1321 
1322 		WebSocketServer::Configuration c;
1323 		c.port = config->port;
1324 		c.enableTls = config->enableTls;
1325 		c.certificatePemFile = config->certificatePemFile
1326 		                           ? make_optional(string(config->certificatePemFile))
1327 		                           : nullopt;
1328 		c.keyPemFile = config->keyPemFile ? make_optional(string(config->keyPemFile)) : nullopt;
1329 		c.keyPemPass = config->keyPemPass ? make_optional(string(config->keyPemPass)) : nullopt;
1330 		auto webSocketServer = std::make_shared<WebSocketServer>(std::move(c));
1331 		int wsserver = emplaceWebSocketServer(webSocketServer);
1332 
1333 		webSocketServer->onClient([wsserver, cb](shared_ptr<WebSocket> webSocket) {
1334 			int ws = emplaceWebSocket(webSocket);
1335 			if (auto ptr = getUserPointer(wsserver)) {
1336 				rtcSetUserPointer(wsserver, *ptr);
1337 				cb(wsserver, ws, *ptr);
1338 			}
1339 		});
1340 
1341 		return wsserver;
1342 	});
1343 }
1344 
rtcDeleteWebSocketServer(int wsserver)1345 RTC_EXPORT int rtcDeleteWebSocketServer(int wsserver) {
1346 	return wrap([&] {
1347 		auto webSocketServer = getWebSocketServer(wsserver);
1348 		webSocketServer->onClient(nullptr);
1349 		webSocketServer->stop();
1350 
1351 		eraseWebSocketServer(wsserver);
1352 		return RTC_ERR_SUCCESS;
1353 	});
1354 }
1355 
rtcGetWebSocketServerPort(int wsserver)1356 RTC_EXPORT int rtcGetWebSocketServerPort(int wsserver) {
1357 	return wrap([&] {
1358 		auto webSocketServer = getWebSocketServer(wsserver);
1359 		return int(webSocketServer->port());
1360 	});
1361 }
1362 
1363 #endif
1364 
rtcPreload()1365 void rtcPreload() {
1366 	try {
1367 		rtc::Preload();
1368 	} catch (const std::exception &e) {
1369 		PLOG_ERROR << e.what();
1370 	}
1371 }
1372 
rtcCleanup()1373 void rtcCleanup() {
1374 	try {
1375 		size_t count = eraseAll();
1376 		if(count != 0) {
1377 			PLOG_INFO << count << " objects were not properly destroyed before cleanup";
1378 		}
1379 
1380 		if(rtc::Cleanup().wait_for(10s) == std::future_status::timeout)
1381 			throw std::runtime_error("Cleanup timeout (possible deadlock or undestructible object)");
1382 
1383 	} catch (const std::exception &e) {
1384 		PLOG_ERROR << e.what();
1385 	}
1386 }
1387 
rtcSetSctpSettings(const rtcSctpSettings * settings)1388 int rtcSetSctpSettings(const rtcSctpSettings *settings) {
1389 	return wrap([&] {
1390 		SctpSettings s = {};
1391 
1392 		if (settings->recvBufferSize > 0)
1393 			s.recvBufferSize = size_t(settings->recvBufferSize);
1394 
1395 		if (settings->sendBufferSize > 0)
1396 			s.sendBufferSize = size_t(settings->sendBufferSize);
1397 
1398 		if (settings->maxChunksOnQueue > 0)
1399 			s.maxChunksOnQueue = size_t(settings->maxChunksOnQueue);
1400 
1401 		if (settings->initialCongestionWindow > 0)
1402 			s.initialCongestionWindow = size_t(settings->initialCongestionWindow);
1403 
1404 		if (settings->maxBurst > 0)
1405 			s.maxBurst = size_t(settings->maxBurst);
1406 		else if (settings->maxBurst < 0)
1407 			s.maxBurst = size_t(0); // setting to 0 disables, not setting chooses optimized default
1408 
1409 		if (settings->congestionControlModule >= 0)
1410 			s.congestionControlModule = unsigned(settings->congestionControlModule);
1411 
1412 		if (settings->delayedSackTimeMs > 0)
1413 			s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
1414 		else if (settings->delayedSackTimeMs < 0)
1415 			s.delayedSackTime = std::chrono::milliseconds(0);
1416 
1417 		if (settings->minRetransmitTimeoutMs > 0)
1418 			s.minRetransmitTimeout = std::chrono::milliseconds(settings->minRetransmitTimeoutMs);
1419 
1420 		if (settings->maxRetransmitTimeoutMs > 0)
1421 			s.maxRetransmitTimeout = std::chrono::milliseconds(settings->maxRetransmitTimeoutMs);
1422 
1423 		if (settings->initialRetransmitTimeoutMs > 0)
1424 			s.initialRetransmitTimeout =
1425 			    std::chrono::milliseconds(settings->initialRetransmitTimeoutMs);
1426 
1427 		if (settings->maxRetransmitAttempts > 0)
1428 			s.maxRetransmitAttempts = settings->maxRetransmitAttempts;
1429 
1430 		if (settings->heartbeatIntervalMs > 0)
1431 			s.heartbeatInterval = std::chrono::milliseconds(settings->heartbeatIntervalMs);
1432 
1433 		SetSctpSettings(std::move(s));
1434 		return RTC_ERR_SUCCESS;
1435 	});
1436 }
1437