Ring Daemon 16.0.0
Loading...
Searching...
No Matches
socket_pair.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 * Copyright (c) 2007 The FFmpeg Project
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19#include <dhtnet/ip_utils.h> // MUST BE INCLUDED FIRST
20
21#include "libav_deps.h" // THEN THIS ONE AFTER
22
23#include "socket_pair.h"
24#include "libav_utils.h"
25#include "logger.h"
27
28#include <dhtnet/ice_socket.h>
29
30#include <iostream>
31#include <string>
32#include <algorithm>
33#include <iterator>
34
35extern "C" {
36#include "srtp.h"
37}
38
39#include <cstring>
40#include <stdexcept>
41#include <unistd.h>
42#include <sys/types.h>
43#include <ciso646> // fix windows compiler bug
44
45#ifdef _WIN32
46#define SOCK_NONBLOCK FIONBIO
47#define poll WSAPoll
48#define close(x) closesocket(x)
49#endif
50
51#ifdef __ANDROID__
52#include <asm-generic/fcntl.h>
53#define SOCK_NONBLOCK O_NONBLOCK
54#endif
55
56#ifdef __APPLE__
57#include <fcntl.h>
58#endif
59
60// Swap 2 byte, 16 bit values:
61#define Swap2Bytes(val) ((((val) >> 8) & 0x00FF) | (((val) << 8) & 0xFF00))
62
63// Swap 4 byte, 32 bit values:
64#define Swap4Bytes(val) \
65 ((((val) >> 24) & 0x000000FF) | (((val) >> 8) & 0x0000FF00) | (((val) << 8) & 0x00FF0000) \
66 | (((val) << 24) & 0xFF000000))
67
68// Swap 8 byte, 64 bit values:
69#define Swap8Bytes(val) \
70 ((((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) \
71 | (((val) >> 24) & 0x0000000000FF0000) | (((val) >> 8) & 0x00000000FF000000) \
72 | (((val) << 8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) \
73 | (((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000))
74
75namespace jami {
76
77static constexpr int NET_POLL_TIMEOUT = 100; /* poll() timeout in ms */
78static constexpr int RTP_MAX_PACKET_LENGTH = 2048;
79static constexpr auto UDP_HEADER_SIZE = 8;
80static constexpr auto SRTP_OVERHEAD = 10;
81static constexpr uint32_t RTCP_RR_FRACTION_MASK = 0xFF000000;
82static constexpr unsigned MINIMUM_RTP_HEADER_SIZE = 16;
83
84enum class DataType : unsigned { RTP = 1 << 0, RTCP = 1 << 1 };
85
87{
88public:
90 const char* out_key,
91 const char* in_suite,
92 const char* in_key)
93 {
96 if (out_suite && out_key) {
97 // XXX: see srtp_open from libavformat/srtpproto.c
99 srtp_close();
100 throw std::runtime_error("Unable to set crypto on output");
101 }
102 }
103
104 if (in_suite && in_key) {
106 srtp_close();
107 throw std::runtime_error("Unable to set crypto on input");
108 }
109 }
110 }
111
112 ~SRTPProtoContext() { srtp_close(); }
113
117
118private:
119 void srtp_close() noexcept
120 {
123 }
124};
125
126static int
128{
129 struct pollfd p = {fd, POLLOUT, 0};
130 auto ret = poll(&p, 1, NET_POLL_TIMEOUT);
131 return ret < 0 ? errno : p.revents & (POLLOUT | POLLERR | POLLHUP) ? 0 : -EAGAIN;
132}
133
134static int
136{
137 int udp_fd = -1;
138
139#ifdef __APPLE__
140 udp_fd = socket(family, SOCK_DGRAM, 0);
141 if (udp_fd >= 0 && fcntl(udp_fd, F_SETFL, O_NONBLOCK) < 0) {
142 close(udp_fd);
143 udp_fd = -1;
144 }
145#elif defined _WIN32
146 udp_fd = socket(family, SOCK_DGRAM, 0);
147 u_long block = 1;
148 if (udp_fd >= 0 && ioctlsocket(udp_fd, FIONBIO, &block) < 0) {
149 close(udp_fd);
150 udp_fd = -1;
151 }
152#else
153 udp_fd = socket(family, SOCK_DGRAM | SOCK_NONBLOCK, 0);
154#endif
155
156 if (udp_fd < 0) {
157 JAMI_ERR("socket() failed");
158 strErr();
159 return -1;
160 }
161
162 auto bind_addr = dhtnet::ip_utils::getAnyHostAddr(family);
163 if (not bind_addr.isIpv4() and not bind_addr.isIpv6()) {
164 JAMI_ERR("No IPv4/IPv6 host found for family %u", family);
165 close(udp_fd);
166 return -1;
167 }
168
169 bind_addr.setPort(port);
170 JAMI_DBG("use local address: %s", bind_addr.toString(true, true).c_str());
171 if (::bind(udp_fd, bind_addr, bind_addr.getLength()) < 0) {
172 JAMI_ERR("bind() failed");
173 strErr();
174 close(udp_fd);
175 udp_fd = -1;
176 }
177
178 return udp_fd;
179}
180
181SocketPair::SocketPair(const char* uri, int localPort)
182{
183 openSockets(uri, localPort);
184}
185
186SocketPair::SocketPair(std::unique_ptr<dhtnet::IceSocket> rtp_sock, std::unique_ptr<dhtnet::IceSocket> rtcp_sock)
187 : rtp_sock_(std::move(rtp_sock))
188 , rtcp_sock_(std::move(rtcp_sock))
189{
190 JAMI_DBG("[%p] Creating instance using ICE sockets for comp %d and %d",
191 this,
192 rtp_sock_->getCompId(),
193 rtcp_sock_->getCompId());
194
195 rtp_sock_->setOnRecv([this](uint8_t* buf, size_t len) {
196 std::lock_guard l(dataBuffMutex_);
197 rtpDataBuff_.emplace_back(buf, buf + len);
198 cv_.notify_one();
199 return len;
200 });
201 rtcp_sock_->setOnRecv([this](uint8_t* buf, size_t len) {
202 std::lock_guard l(dataBuffMutex_);
203 rtcpDataBuff_.emplace_back(buf, buf + len);
204 cv_.notify_one();
205 return len;
206 });
207}
208
210{
211 interrupt();
212 closeSockets();
213 JAMI_DBG("[%p] Instance destroyed", this);
214}
215
216bool
218{
219 std::unique_lock lock(rtcpInfo_mutex_);
220 return cvRtcpPacketReadyToRead_.wait_for(lock, interval, [this] {
221 return interrupted_ or not listRtcpRRHeader_.empty() or not listRtcpREMBHeader_.empty();
222 });
223}
224
225void
226SocketPair::saveRtcpRRPacket(uint8_t* buf, size_t len)
227{
228 if (len < sizeof(rtcpRRHeader))
229 return;
230
231 auto header = reinterpret_cast<rtcpRRHeader*>(buf);
232 if (header->pt != 201) // 201 = RR PT
233 return;
234
235 std::lock_guard lock(rtcpInfo_mutex_);
236
237 if (listRtcpRRHeader_.size() >= MAX_LIST_SIZE) {
238 listRtcpRRHeader_.pop_front();
239 }
240
241 listRtcpRRHeader_.emplace_back(*header);
242
243 cvRtcpPacketReadyToRead_.notify_one();
244}
245
246void
247SocketPair::saveRtcpREMBPacket(uint8_t* buf, size_t len)
248{
249 if (len < sizeof(rtcpREMBHeader))
250 return;
251
252 auto header = reinterpret_cast<rtcpREMBHeader*>(buf);
253 if (header->pt != 206) // 206 = REMB PT
254 return;
255
256 if (header->uid != 0x424D4552) // uid must be "REMB"
257 return;
258
259 std::lock_guard lock(rtcpInfo_mutex_);
260
261 if (listRtcpREMBHeader_.size() >= MAX_LIST_SIZE) {
262 listRtcpREMBHeader_.pop_front();
263 }
264
265 listRtcpREMBHeader_.push_back(*header);
266
267 cvRtcpPacketReadyToRead_.notify_one();
268}
269
270std::list<rtcpRRHeader>
272{
273 std::lock_guard lock(rtcpInfo_mutex_);
274 return std::move(listRtcpRRHeader_);
275}
276
277std::list<rtcpREMBHeader>
279{
280 std::lock_guard lock(rtcpInfo_mutex_);
281 return std::move(listRtcpREMBHeader_);
282}
283
284void
286 const char* out_key,
287 const char* in_suite,
288 const char* in_key)
289{
290 srtpContext_.reset(new SRTPProtoContext(out_suite, out_key, in_suite, in_key));
291}
292
293void
295{
296 JAMI_WARN("[%p] Interrupting RTP sockets", this);
297 interrupted_ = true;
298 if (rtp_sock_)
299 rtp_sock_->setOnRecv(nullptr);
300 if (rtcp_sock_)
301 rtcp_sock_->setOnRecv(nullptr);
302 cv_.notify_all();
303 cvRtcpPacketReadyToRead_.notify_all();
304}
305
306void
308{
309 JAMI_DBG("[%p] Read operations in blocking mode [%s]", this, block ? "YES" : "NO");
310 readBlockingMode_ = block;
311 cv_.notify_all();
312 cvRtcpPacketReadyToRead_.notify_all();
313}
314
315void
317{
318 noWrite_ = state;
319}
320
321void
323{
324 if (rtcpHandle_ > 0 and close(rtcpHandle_))
325 strErr();
326 if (rtpHandle_ > 0 and close(rtpHandle_))
327 strErr();
328}
329
330void
332{
333 JAMI_DBG("Creating rtp socket for uri %s on port %d", uri, local_rtp_port);
334
335 char hostname[256];
336 char path[1024];
337 int dst_rtp_port;
338
339 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &dst_rtp_port, path, sizeof(path), uri);
340
341 const int local_rtcp_port = local_rtp_port + 1;
342 const int dst_rtcp_port = dst_rtp_port + 1;
343
344 rtpDestAddr_ = dhtnet::IpAddr {hostname};
345 rtpDestAddr_.setPort(dst_rtp_port);
346 rtcpDestAddr_ = dhtnet::IpAddr {hostname};
347 rtcpDestAddr_.setPort(dst_rtcp_port);
348
349 // Open local sockets (RTP/RTCP)
350 if ((rtpHandle_ = udp_socket_create(rtpDestAddr_.getFamily(), local_rtp_port)) == -1
351 or (rtcpHandle_ = udp_socket_create(rtcpDestAddr_.getFamily(), local_rtcp_port)) == -1) {
352 closeSockets();
353 JAMI_ERR("[%p] Sockets creation failed", this);
354 throw std::runtime_error("Sockets creation failed");
355 }
356
357 JAMI_WARN("SocketPair: local{%d,%d} / %s{%d,%d}",
360 hostname,
363}
364
367{
368 unsigned ip_header_size;
369 if (rtp_sock_)
370 ip_header_size = rtp_sock_->getTransportOverhead();
371 else if (rtpDestAddr_.getFamily() == AF_INET6)
372 ip_header_size = 40;
373 else
374 ip_header_size = 20;
375 return new MediaIOHandle(
376 mtu - (srtpContext_ ? SRTP_OVERHEAD : 0) - UDP_HEADER_SIZE - ip_header_size,
377 true,
378 [](void* sp, uint8_t* buf, int len) {
379 return static_cast<SocketPair*>(sp)->readCallback(buf, len);
380 },
381 [](void* sp, uint8_t* buf, int len) {
382 return static_cast<SocketPair*>(sp)->writeCallback(buf, len);
383 },
384 0,
385 reinterpret_cast<void*>(this));
386}
387
388int
389SocketPair::waitForData()
390{
391 // System sockets
392 if (rtpHandle_ >= 0) {
393 int ret;
394 do {
395 if (interrupted_) {
396 errno = EINTR;
397 return -1;
398 }
399
400 if (not readBlockingMode_) {
401 return 0;
402 }
403
404 // work with system socket
405 struct pollfd p[2] = {{rtpHandle_, POLLIN, 0}, {rtcpHandle_, POLLIN, 0}};
406 ret = poll(p, 2, NET_POLL_TIMEOUT);
407 if (ret > 0) {
408 ret = 0;
409 if (p[0].revents & POLLIN)
410 ret |= static_cast<int>(DataType::RTP);
411 if (p[1].revents & POLLIN)
412 ret |= static_cast<int>(DataType::RTCP);
413 }
414 } while (!ret or (ret < 0 and errno == EAGAIN));
415
416 return ret;
417 }
418
419 // work with IceSocket
420 {
421 std::unique_lock lk(dataBuffMutex_);
422 cv_.wait(lk, [this] {
423 return interrupted_ or not rtpDataBuff_.empty() or not rtcpDataBuff_.empty()
424 or not readBlockingMode_;
425 });
426 }
427
428 if (interrupted_) {
429 errno = EINTR;
430 return -1;
431 }
432
433 return static_cast<int>(DataType::RTP) | static_cast<int>(DataType::RTCP);
434}
435
436int
437SocketPair::readRtpData(void* buf, int buf_size)
438{
439 // handle system socket
440 if (rtpHandle_ >= 0) {
441 struct sockaddr_storage from;
442 socklen_t from_len = sizeof(from);
443 return recvfrom(rtpHandle_,
444 static_cast<char*>(buf),
445 buf_size,
446 0,
447 reinterpret_cast<struct sockaddr*>(&from),
448 &from_len);
449 }
450
451 // handle ICE
452 std::unique_lock lk(dataBuffMutex_);
453 if (not rtpDataBuff_.empty()) {
454 auto pkt = std::move(rtpDataBuff_.front());
455 rtpDataBuff_.pop_front();
456 lk.unlock(); // to not block our ICE callbacks
457 int pkt_size = pkt.size();
458 int len = std::min(pkt_size, buf_size);
459 std::copy_n(pkt.begin(), len, static_cast<char*>(buf));
460 return len;
461 }
462
463 return 0;
464}
465
466int
467SocketPair::readRtcpData(void* buf, int buf_size)
468{
469 // handle system socket
470 if (rtcpHandle_ >= 0) {
471 struct sockaddr_storage from;
472 socklen_t from_len = sizeof(from);
473 return recvfrom(rtcpHandle_,
474 static_cast<char*>(buf),
475 buf_size,
476 0,
477 reinterpret_cast<struct sockaddr*>(&from),
478 &from_len);
479 }
480
481 // handle ICE
482 std::unique_lock lk(dataBuffMutex_);
483 if (not rtcpDataBuff_.empty()) {
484 auto pkt = std::move(rtcpDataBuff_.front());
485 rtcpDataBuff_.pop_front();
486 lk.unlock();
487 int pkt_size = pkt.size();
488 int len = std::min(pkt_size, buf_size);
489 std::copy_n(pkt.begin(), len, static_cast<char*>(buf));
490 return len;
491 }
492
493 return 0;
494}
495
496int
497SocketPair::readCallback(uint8_t* buf, int buf_size)
498{
499 auto datatype = waitForData();
500 if (datatype < 0)
501 return datatype;
502
503 int len = 0;
504 bool fromRTCP = false;
505
506 if (datatype & static_cast<int>(DataType::RTCP)) {
507 len = readRtcpData(buf, buf_size);
508 if (len > 0) {
509 auto header = reinterpret_cast<rtcpRRHeader*>(buf);
510 // 201 = RR PT
511 if (header->pt == 201) {
512 lastDLSR_ = Swap4Bytes(header->dlsr);
513 // JAMI_WARN("Read RR, lastDLSR : %d", lastDLSR_);
514 lastRR_time = std::chrono::steady_clock::now();
515 saveRtcpRRPacket(buf, len);
516 }
517 // 206 = REMB PT
518 else if (header->pt == 206)
519 saveRtcpREMBPacket(buf, len);
520 // 200 = SR PT
521 else if (header->pt == 200) {
522 // not used yet
523 } else {
524 JAMI_DBG("Unable to read RTCP: unknown packet type %u", header->pt);
525 }
526 fromRTCP = true;
527 }
528 }
529
530 // No RTCP… attempt RTP
531 if (!len and (datatype & static_cast<int>(DataType::RTP))) {
532 len = readRtpData(buf, buf_size);
533 fromRTCP = false;
534 }
535
536 if (len <= 0)
537 return len;
538
539 if (not fromRTCP && (buf_size < static_cast<int>(MINIMUM_RTP_HEADER_SIZE)))
540 return len;
541
542 // SRTP decrypt
543 if (not fromRTCP and srtpContext_ and srtpContext_->srtp_in.aes) {
544 int32_t gradient = 0;
545 int32_t deltaT = 0;
546 float abs = 0.0f;
547 bool res_parse = false;
548 bool res_delay = false;
549
550 res_parse = parse_RTP_ext(buf, &abs);
551 bool marker = (buf[1] & 0x80) >> 7;
552
553 if (res_parse)
554 res_delay = getOneWayDelayGradient(abs, marker, &gradient, &deltaT);
555
556 // rtpDelayCallback_ is not set for audio
557 if (rtpDelayCallback_ and res_delay)
558 rtpDelayCallback_(gradient, deltaT);
559
560 auto err = ff_srtp_decrypt(&srtpContext_->srtp_in, buf, &len);
561 if (packetLossCallback_ and (buf[2] << 8 | buf[3]) != lastSeqNumIn_ + 1)
562 packetLossCallback_();
563 lastSeqNumIn_ = buf[2] << 8 | buf[3];
564 if (err < 0)
565 JAMI_WARN("decrypt error %d", err);
566 }
567
568 if (len != 0)
569 return len;
570 else
571 return AVERROR_EOF;
572}
573
574int
576{
577 bool isRTCP = RTP_PT_IS_RTCP(buf[1]);
578
579 // System sockets?
580 if (rtpHandle_ >= 0) {
581 int fd;
582 dhtnet::IpAddr* dest_addr;
583
584 if (isRTCP) {
585 fd = rtcpHandle_;
586 dest_addr = &rtcpDestAddr_;
587 } else {
588 fd = rtpHandle_;
589 dest_addr = &rtpDestAddr_;
590 }
591
592 auto ret = ff_network_wait_fd(fd);
593 if (ret < 0)
594 return ret;
595
596 if (noWrite_)
597 return buf_size;
598 return ::sendto(fd,
599 reinterpret_cast<const char*>(buf),
600 buf_size,
601 0,
602 *dest_addr,
603 dest_addr->getLength());
604 }
605
606 if (noWrite_)
607 return buf_size;
608
609 // IceSocket
610 if (isRTCP)
611 return rtcp_sock_->send(buf, buf_size);
612 else
613 return rtp_sock_->send(buf, buf_size);
614}
615
616int
617SocketPair::writeCallback(uint8_t* buf, int buf_size)
618{
619 if (noWrite_)
620 return 0;
621
622 int ret;
623 bool isRTCP = RTP_PT_IS_RTCP(buf[1]);
624 unsigned int ts_LSB, ts_MSB;
626
627 // Encrypt?
628 if (not isRTCP and srtpContext_ and srtpContext_->srtp_out.aes) {
629 buf_size = ff_srtp_encrypt(&srtpContext_->srtp_out,
630 buf,
631 buf_size,
632 srtpContext_->encryptbuf,
633 sizeof(srtpContext_->encryptbuf));
634 if (buf_size < 0) {
635 JAMI_WARN("encrypt error %d", buf_size);
636 return buf_size;
637 }
638
639 buf = srtpContext_->encryptbuf;
640 }
641
642 // check if we're sending an RR, if so, detect packet loss
643 // buf_size gives length of buffer, not just header
644 if (isRTCP && static_cast<unsigned>(buf_size) >= sizeof(rtcpRRHeader)) {
645 auto header = reinterpret_cast<rtcpRRHeader*>(buf);
646 rtcpPacketLoss_ = (header->pt == 201
647 && ntohl(header->fraction_lost) & RTCP_RR_FRACTION_MASK);
648 }
649
650 do {
651 if (interrupted_)
652 return -EINTR;
654 } while (ret < 0 and errno == EAGAIN);
655
656 if (buf[1] == 200) // Sender Report
657 {
658 auto header = reinterpret_cast<rtcpSRHeader*>(buf);
659 ts_LSB = Swap4Bytes(header->timestampLSB);
660 ts_MSB = Swap4Bytes(header->timestampMSB);
661
662 currentSRTS = ts_MSB + (ts_LSB / pow(2, 32));
663
664 if (lastSRTS_ != 0 && lastDLSR_ != 0) {
665 if (histoLatency_.size() >= MAX_LIST_SIZE)
666 histoLatency_.pop_front();
667
668 currentLatency = (currentSRTS - lastSRTS_) / 2;
669 // JAMI_WARN("Current Latency : %f from sender %X", currentLatency, header->ssrc);
670 histoLatency_.push_back(currentLatency);
671 }
672
673 lastSRTS_ = currentSRTS;
674
675 // JAMI_WARN("SENDING NEW RTCP SR !! ");
676
677 } else if (buf[1] == 201) // Receiver Report
678 {
679 // auto header = reinterpret_cast<rtcpRRHeader*>(buf);
680 // JAMI_WARN("SENDING NEW RTCP RR !! ");
681 }
682
683 return ret < 0 ? -errno : ret;
684}
685
686double
688{
689 if (not histoLatency_.empty())
690 return histoLatency_.back();
691 else
692 return -1;
693}
694
695void
696SocketPair::setRtpDelayCallback(std::function<void(int, int)> cb)
697{
698 rtpDelayCallback_ = std::move(cb);
699}
700
701bool
702SocketPair::getOneWayDelayGradient(float sendTS, bool marker, int32_t* gradient, int32_t* deltaT)
703{
704 // Keep only last packet of each frame
705 if (not marker) {
706 return 0;
707 }
708
709 // 1st frame
710 if (not lastSendTS_) {
711 lastSendTS_ = sendTS;
712 lastReceiveTS_ = std::chrono::steady_clock::now();
713 return 0;
714 }
715
716 int32_t deltaS = (sendTS - lastSendTS_) * 1000; // milliseconds
717 if (deltaS < 0)
718 deltaS += 64000;
719 lastSendTS_ = sendTS;
720
721 std::chrono::steady_clock::time_point arrival_TS = std::chrono::steady_clock::now();
722 auto deltaR = std::chrono::duration_cast<std::chrono::milliseconds>(arrival_TS - lastReceiveTS_)
723 .count();
724 lastReceiveTS_ = arrival_TS;
725
727 *deltaT = deltaR;
728
729 return true;
730}
731
732bool
733SocketPair::parse_RTP_ext(uint8_t* buf, float* abs)
734{
735 if (not(buf[0] & 0x10))
736 return false;
737
738 uint16_t magic_word = (buf[12] << 8) + buf[13];
739 if (magic_word != 0xBEDE)
740 return false;
741
742 uint8_t sec = buf[17] >> 2;
743 uint32_t fract = ((buf[17] & 0x3) << 16 | (buf[18] << 8) | buf[19]) << 14;
744 float milli = fract / pow(2, 32);
745
746 *abs = sec + (milli);
747 return true;
748}
749
752{
753 if (srtpContext_)
754 return srtpContext_->srtp_out.seq_largest;
755 JAMI_ERR("SRTP context not found.");
756 return 0;
757}
758
759} // namespace jami
uint8_t encryptbuf[RTP_MAX_PACKET_LENGTH]
SRTPProtoContext(const char *out_suite, const char *out_key, const char *in_suite, const char *in_key)
void openSockets(const char *uri, int localPort)
void setReadBlockingMode(bool blocking)
void setRtpDelayCallback(std::function< void(int, int)> cb)
int writeData(uint8_t *buf, int buf_size)
MediaIOHandle * createIOContext(const uint16_t mtu)
std::list< rtcpREMBHeader > getRtcpREMB()
std::list< rtcpRRHeader > getRtcpRR()
uint16_t lastSeqValOut()
double getLastLatency()
bool waitForRTCP(std::chrono::seconds interval)
SocketPair(const char *uri, int localPort)
void createSRTP(const char *out_suite, const char *out_params, const char *in_suite, const char *in_params)
void stopSendOp(bool state=true)
#define JAMI_ERR(...)
Definition logger.h:218
#define JAMI_DBG(...)
Definition logger.h:216
#define JAMI_WARN(...)
Definition logger.h:217
void ring_secure_memzero(void *ptr, size_t length)
Definition memory.cpp:45
static int ff_network_wait_fd(int fd)
rational< I > abs(const rational< I > &r)
Definition rational.h:234
static constexpr auto UDP_HEADER_SIZE
void emitSignal(Args... args)
Definition ring_signal.h:64
static int udp_socket_create(int family, int port)
static constexpr auto SRTP_OVERHEAD
static constexpr unsigned MINIMUM_RTP_HEADER_SIZE
void strErr()
Thread-safe function to print the stringified contents of errno.
Definition logger.cpp:105
static constexpr int RTP_MAX_PACKET_LENGTH
static constexpr uint32_t RTCP_RR_FRACTION_MASK
static constexpr int NET_POLL_TIMEOUT
#define Swap4Bytes(val)
int ff_srtp_encrypt(struct SRTPContext *s, const uint8_t *in, int len, uint8_t *out, int outlen)
int ff_srtp_set_crypto(struct SRTPContext *s, const char *suite, const char *params)
#define RTP_PT_IS_RTCP(x)
Definition srtp.h:54
int ff_srtp_decrypt(struct SRTPContext *s, uint8_t *buf, int *lenptr)
void ff_srtp_free(struct SRTPContext *s)