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