Compare commits

...

43 Commits

Author SHA1 Message Date
4cdb788124 Merge pull request #439 from paullouisageneau/change-plog-check
Change plog check
2021-06-11 08:03:57 +02:00
6255ff1995 Check for PLOG_DEFAULT_INSTANCE_ID instead of PLOG 2021-06-11 07:52:37 +02:00
1d47294050 Merge pull request #437 from murat-dogan/master
Fix typo
2021-06-08 14:40:27 +02:00
86f93e9aa3 Fix typo 2021-06-08 11:59:08 +03:00
d218e7923c Cleaned up std:: prefix where possible 2021-06-04 11:28:19 +02:00
2d97cc18c6 Fixed removeSSRC() to update SSRC list in addition to attributes 2021-06-04 11:25:08 +02:00
76d2d3d97f Properly check input in RTPMap::setMLine() 2021-06-03 21:24:39 +02:00
1156fbe434 Merge pull request #431 from in2core/feature/improve-capi-sscr
Improve capi for ssrc manipulation
2021-06-03 13:06:42 +02:00
983b5759f3 Replace memcpy with std::copy in copyAndReturn 2021-06-03 09:30:17 +02:00
79242e27ed Fix cname parsing bug in parseSdpLine 2021-06-03 09:29:45 +02:00
39e51a8345 Rename bufferSize parameter to count 2021-06-01 11:28:44 +02:00
f4aae34874 Refactor rtcIsDataChannelOpen to rtcIsOpen 2021-06-01 11:28:15 +02:00
34469d16ae Add CName parsing from ssrc 2021-06-01 11:27:41 +02:00
e6a9650523 Fix incorrect size in memcpy (copyAndReturn) 2021-06-01 11:26:32 +02:00
a9057a02e5 move lowercased function to RTC_ENABLE_MEDIA 2021-05-31 15:24:22 +02:00
a2b019465c Move ssrc manupulation functions to RTC_ENABLE_MEDIA 2021-05-31 15:20:18 +02:00
8bdce69ab7 Fix build error: comparison of integer expressions of different signedness 2021-05-31 15:09:11 +02:00
78ca3a318f fix getCNameForSsrc 2021-05-31 14:53:13 +02:00
e88197646d Fix code duplication 2021-05-31 14:52:55 +02:00
c5e4b972c2 Improve capi for ssrc manipulation 2021-05-31 14:32:36 +02:00
4cdde18e4b Merge branch 'v0.13' 2021-05-29 19:25:12 +02:00
41cba8a35a Bumped version to 0.13.3 2021-05-29 19:23:02 +02:00
6c683b326d Added ostream operator for LogLevel 2021-05-29 19:22:28 +02:00
a152edf256 Merge pull request #429 from paullouisageneau/ostream-loglevel
Add ostream operator for LogLevel
2021-05-29 19:19:46 +02:00
8f50eeb0f2 Added ostream operator for LogLevel 2021-05-29 19:12:57 +02:00
1105a4faec Merge branch 'v0.13' 2021-05-28 23:09:10 +02:00
8184d1d60e Updated libjuice to v0.7.4 2021-05-28 23:07:57 +02:00
38e1a946b0 Cleaned up includes in sctptransport.hpp 2021-05-28 22:06:28 +02:00
8522446d6c Merge branch 'v0.13' 2021-05-28 21:57:57 +02:00
8da8c8a6d0 Bumped version to v0.13.2 2021-05-28 21:56:21 +02:00
6a4a22a87c Fixed reference when iterating on prefixes array 2021-05-28 21:54:03 +02:00
724fefbfdb Merge pull request #428 from paullouisageneau/fix-sctp-global-instances-set
Fix possible static de-initialization order issue in SctpTransport
2021-05-28 21:50:39 +02:00
83cc26d4a5 Fixed possible static deinit order issue with SctpTransport instances set 2021-05-28 21:49:55 +02:00
1cfefd9dcd Updated description 2021-05-27 08:18:41 +02:00
fbe141301c Added bindAddress configuration setting in Doc 2021-05-22 16:43:57 +02:00
811a6b8a26 Merge pull request #426 from paullouisageneau/sctp-rto-rtx
Expose more SCTP settings and reduce min RTO
2021-05-20 14:38:56 +02:00
ddbd963e7e Reduced SCTP min RTO to 200ms 2021-05-20 14:29:15 +02:00
05a37c8306 Allowed disabling delayed SACK from C API 2021-05-20 14:10:07 +02:00
a9ca8b687b Exposed SCTP RTO and RTX settings 2021-05-20 14:06:44 +02:00
e91880141a Merge branch 'v0.13' 2021-05-17 19:09:21 +02:00
5c8d63ad78 Merge pull request #425 from paullouisageneau/bind-address
Add bind address in configuration
2021-05-17 15:32:12 +02:00
c5cb81762c Added bindAddress configuration setting 2021-05-17 15:20:58 +02:00
0b50fc4bb0 Updated libjuice 2021-05-17 15:01:16 +02:00
17 changed files with 365 additions and 96 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.7)
project(libdatachannel
VERSION 0.13.1
VERSION 0.13.3
LANGUAGES CXX)
set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")

1
DOC.md
View File

@ -86,6 +86,7 @@ Arguments:
- `config`: the configuration structure, containing:
- `iceServers` (optional): an array of pointers on null-terminated ice server URIs (NULL if unused)
- `iceServersCount` (optional): number of URLs in the array pointed by `iceServers` (0 if unused)
- `bindAddress` (optional): if non-NULL, bind only to the given local address (ignored with libnice as ICE backend)
- `certificateType` (optional): certificate type, either `RTC_CERTIFICATE_ECDSA` or `RTC_CERTIFICATE_RSA` (0 or `RTC_CERTIFICATE_DEFAULT` if default)
- `enableIceTcp`: if true, generate TCP candidates for ICE (ignored with libjuice as ICE backend)
- `disableAutoNegotiation`: if true, the user is responsible for calling `rtcSetLocalDescription` after creating a Data Channel and after setting the remote description

View File

@ -1,4 +1,4 @@
# libdatachannel - C/C++ WebRTC Data Channels
# libdatachannel - C/C++ WebRTC lightweight library
libdatachannel is a standalone implementation of WebRTC Data Channels, WebRTC Media Transport, and WebSockets in C++17 with C bindings for POSIX platforms (including GNU/Linux, Android, and Apple macOS) and Microsoft Windows.

2
deps/libjuice vendored

View File

@ -3,7 +3,7 @@
This directory contains a native client to open Data Channels with WebSocket signaling using libdatachannel and benchmark functionalities. It offers three functionalities;
- Benchmark: Bi-directional data transfer benchmark (Also supports One-Way testing)
- Constant Throughput Set: Send desired amount of data per second
- Multiple Data Channel: Create desried count of data channel
- Multiple Data Channel: Create desired amount of data channel
## Start Signaling Server
- Start one of the signaling server from the examples folder. For example start `signaling-server-nodejs` like;

View File

@ -74,6 +74,7 @@ struct RTC_CPP_EXPORT Configuration {
// ICE settings
std::vector<IceServer> iceServers;
optional<ProxyServer> proxyServer; // libnice only
optional<string> bindAddress; // libjuice only, default any
// Options
CertificateType certificateType = CertificateType::Default;

View File

@ -144,12 +144,14 @@ public:
void removeFormat(const string &fmt);
void addSSRC(uint32_t ssrc, optional<string> name,
optional<string> msid = nullopt, optional<string> trackID = nullopt);
void addSSRC(uint32_t ssrc, optional<string> name, optional<string> msid = nullopt,
optional<string> trackID = nullopt);
void removeSSRC(uint32_t oldSSRC);
void replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, optional<string> name,
optional<string> msid = nullopt, optional<string> trackID = nullopt);
optional<string> msid = nullopt, optional<string> trackID = nullopt);
bool hasSSRC(uint32_t ssrc);
std::vector<uint32_t> getSSRCs();
std::optional<std::string> getCNameForSsrc(uint32_t ssrc);
void setBitrate(int bitrate);
int getBitrate() const;
@ -181,6 +183,8 @@ public:
void setMLine(string_view view);
};
void addRTPMap(const RTPMap &map);
std::map<int, RTPMap>::iterator beginMaps();
std::map<int, RTPMap>::iterator endMaps();
std::map<int, RTPMap>::iterator removeMap(std::map<int, RTPMap>::iterator iterator);
@ -195,33 +199,25 @@ public:
std::map<int, RTPMap> mRtpMap;
std::vector<uint32_t> mSsrcs;
public:
void addRTPMap(const RTPMap &map);
void removeSSRC(uint32_t oldSSRC);
std::map<uint32_t, string> mCNameMap;
};
class RTC_CPP_EXPORT Audio : public Media {
public:
Audio(string mid = "audio", Direction dir = Direction::SendOnly);
void addAudioCodec(int payloadType, string codec,
optional<string> profile = std::nullopt);
void addAudioCodec(int payloadType, string codec, optional<string> profile = std::nullopt);
void addOpusCodec(int payloadType,
optional<string> profile = DEFAULT_OPUS_AUDIO_PROFILE);
void addOpusCodec(int payloadType, optional<string> profile = DEFAULT_OPUS_AUDIO_PROFILE);
};
class RTC_CPP_EXPORT Video : public Media {
public:
Video(string mid = "video", Direction dir = Direction::SendOnly);
void addVideoCodec(int payloadType, string codec,
optional<string> profile = std::nullopt);
void addVideoCodec(int payloadType, string codec, optional<string> profile = std::nullopt);
void addH264Codec(int payloadType,
optional<string> profile = DEFAULT_H264_VIDEO_PROFILE);
void addH264Codec(int payloadType, optional<string> profile = DEFAULT_H264_VIDEO_PROFILE);
void addVP8Codec(int payloadType);
void addVP9Codec(int payloadType);
};

View File

@ -22,6 +22,7 @@
#include "common.hpp"
#include <chrono>
#include <iostream>
namespace rtc {
@ -38,12 +39,12 @@ enum class LogLevel { // Don't change, it must match plog severity
typedef std::function<void(LogLevel level, string message)> LogCallback;
RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr);
#ifdef PLOG
#ifdef PLOG_DEFAULT_INSTANCE_ID
RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
#endif
RTC_EXPORT void Preload();
RTC_EXPORT void Cleanup();
RTC_CPP_EXPORT void Preload();
RTC_CPP_EXPORT void Cleanup();
struct SctpSettings {
// For the following settings, not set means optimized default
@ -54,10 +55,17 @@ struct SctpSettings {
optional<size_t> maxBurst; // in MTUs
optional<unsigned int> congestionControlModule; // 0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC
optional<std::chrono::milliseconds> delayedSackTime;
optional<std::chrono::milliseconds> minRetransmitTimeout;
optional<std::chrono::milliseconds> maxRetransmitTimeout;
optional<std::chrono::milliseconds> initialRetransmitTimeout;
optional<unsigned int> maxRetransmitAttempts;
optional<std::chrono::milliseconds> heartbeatInterval;
};
RTC_EXPORT void SetSctpSettings(SctpSettings s);
RTC_CPP_EXPORT void SetSctpSettings(SctpSettings s);
} // namespace rtc
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level);
#endif

View File

@ -150,13 +150,14 @@ RTC_EXPORT void *rtcGetUserPointer(int i);
typedef struct {
const char **iceServers;
int iceServersCount;
const char *bindAddress; // libjuice only, NULL means any
rtcCertificateType certificateType;
bool enableIceTcp;
bool disableAutoNegotiation;
uint16_t portRangeBegin;
uint16_t portRangeEnd;
int mtu; // <= 0 means automatic
int maxMessageSize; // <= 0 means default
uint16_t portRangeBegin; // 0 means automatic
uint16_t portRangeEnd; // 0 means automatic
int mtu; // <= 0 means automatic
int maxMessageSize; // <= 0 means default
} rtcConfiguration;
RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
@ -205,6 +206,7 @@ RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
const rtcDataChannelInit *init); // returns dc id
RTC_EXPORT int rtcIsOpen(int dc);
RTC_EXPORT int rtcDeleteDataChannel(int dc);
RTC_EXPORT int rtcGetDataChannelStream(int dc);
@ -253,6 +255,13 @@ typedef struct {
uint32_t timestamp; // Start timestamp
} rtcStartTime;
typedef struct {
uint32_t ssrc;
const char *name; // optional
const char *msid; // optional
const char *trackId; // optional, track ID used in MSID
} rtcSsrcForTypeInit;
// Set H264PacketizationHandler for track
RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
@ -297,6 +306,22 @@ RTC_EXPORT int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timest
// Set NeedsToReport flag in RtcpSrReporter handler identified by given track id
RTC_EXPORT int rtcSetNeedsToSendRtcpSr(int id);
/// Get all available payload types for given codec and stores them in buffer, does nothing if buffer is NULL
int rtcGetTrackPayloadTypesForCodec(int tr, const char * ccodec, int * buffer, int size);
/// Get all SSRCs for given track
int rtcGetSsrcsForTrack(int tr, uint32_t * buffer, int count);
/// Get CName for SSRC
int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char * cname, int cnameSize);
/// Get all SSRCs for given media type in given SDP
/// @param mediaType Media type (audio/video)
int rtcGetSsrcsForType(const char * mediaType, const char * sdp, uint32_t * buffer, int bufferSize);
/// Set SSRC for given media type in given SDP
int rtcSetSsrcForType(const char * mediaType, const char * sdp, char * buffer, const int bufferSize, rtcSsrcForTypeInit * init);
#endif // RTC_ENABLE_MEDIA
#if RTC_ENABLE_WEBSOCKET
@ -339,13 +364,18 @@ RTC_EXPORT void rtcCleanup(void);
// SCTP global settings
typedef struct {
int recvBufferSize; // in bytes, <= 0 means optimized default
int sendBufferSize; // in bytes, <= 0 means optimized default
int maxChunksOnQueue; // in chunks, <= 0 means optimized default
int initialCongestionWindow; // in MTUs, <= 0 means optimized default
int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled
int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC
int delayedSackTimeMs; // in msecs, <= 0 means optimized default
int recvBufferSize; // in bytes, <= 0 means optimized default
int sendBufferSize; // in bytes, <= 0 means optimized default
int maxChunksOnQueue; // in chunks, <= 0 means optimized default
int initialCongestionWindow; // in MTUs, <= 0 means optimized default
int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled
int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC
int delayedSackTimeMs; // in msecs, 0 means optimized default, < 0 means disabled
int minRetransmitTimeoutMs; // in msecs, <= 0 means optimized default
int maxRetransmitTimeoutMs; // in msecs, <= 0 means optimized default
int initialRetransmitTimeoutMs; // in msecs, <= 0 means optimized default
int maxRetransmitAttempts; // number of retransmissions, <= 0 means optimized default
int heartbeatIntervalMs; // in msecs, <= 0 means optimized default
} rtcSctpSettings;
// Note: SCTP settings apply to newly-created PeerConnections only

View File

@ -93,7 +93,7 @@ void Candidate::parse(string candidate) {
{"so", TransportType::TcpSo}};
const std::array prefixes{"a=", "candidate:"};
for (const string &prefix : prefixes)
for (string prefix : prefixes)
if (match_prefix(candidate, prefix))
candidate.erase(0, prefix.size());

View File

@ -268,6 +268,24 @@ int copyAndReturn(binary b, char *buffer, int size) {
return int(b.size());
}
template<typename T>
int copyAndReturn(std::vector<T> b, T *buffer, int size) {
if (!buffer)
return int(b.size());
if (size < int(b.size()))
return RTC_ERR_TOO_SMALL;
std::copy(b.begin(), b.end(), buffer);
return int(b.size());
}
#if RTC_ENABLE_MEDIA
// function is used in RTC_ENABLE_MEDIA only
string lowercased(string str) {
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
return str;
}
#endif // RTC_ENABLE_MEDIA
} // namespace
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
@ -290,15 +308,18 @@ int rtcCreatePeerConnection(const rtcConfiguration *config) {
for (int i = 0; i < config->iceServersCount; ++i)
c.iceServers.emplace_back(string(config->iceServers[i]));
c.certificateType = static_cast<CertificateType>(config->certificateType);
c.enableIceTcp = config->enableIceTcp;
c.disableAutoNegotiation = config->disableAutoNegotiation;
if (config->bindAddress)
c.bindAddress = string(config->bindAddress);
if (config->portRangeBegin > 0 || config->portRangeEnd > 0) {
c.portRangeBegin = config->portRangeBegin;
c.portRangeEnd = config->portRangeEnd;
}
c.certificateType = static_cast<CertificateType>(config->certificateType);
c.enableIceTcp = config->enableIceTcp;
c.disableAutoNegotiation = config->disableAutoNegotiation;
if (config->mtu > 0)
c.mtu = size_t(config->mtu);
@ -362,6 +383,12 @@ int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *
});
}
int rtcIsOpen(int cid) {
return wrap([cid] {
return getChannel(cid)->isOpen();
});
}
int rtcDeleteDataChannel(int dc) {
return wrap([dc] {
auto dataChannel = getDataChannel(dc);
@ -500,6 +527,26 @@ int rtcGetTrackDescription(int tr, char *buffer, int size) {
#if RTC_ENABLE_MEDIA
void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid, const char *_trackID) {
optional<string> name = nullopt;
if (_name) {
name = string(_name);
}
optional<string> msid = nullopt;
if (_msid) {
msid = string(_msid);
}
optional<string> trackID = nullopt;
if (_trackID) {
trackID = string(_trackID);
}
description->addSSRC(ssrc, name, msid, trackID);
}
int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
return wrap([&] {
auto track = getTrack(tr);
@ -630,6 +677,85 @@ int rtcSetNeedsToSendRtcpSr(int id) {
});
}
int rtcGetTrackPayloadTypesForCodec(int tr, const char * ccodec, int * buffer, int size) {
return wrap([&] {
auto track = getTrack(tr);
auto codec = lowercased(string(ccodec));
auto description = track->description();
std::vector<int> payloadTypes{};
payloadTypes.reserve(std::max(size, 0));
for (auto it = description.beginMaps(); it != description.endMaps(); it++) {
auto element = *it;
if (lowercased(element.second.format) == codec) {
payloadTypes.push_back(element.first);
}
}
return copyAndReturn(payloadTypes, buffer, size);
});
}
int rtcGetSsrcsForTrack(int tr, uint32_t * buffer, int count) {
return wrap([&] {
auto track = getTrack(tr);
auto ssrcs = track->description().getSSRCs();
return copyAndReturn(ssrcs, buffer, count);
});
}
int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char * cname, int cnameSize) {
return wrap([&] {
auto track = getTrack(tr);
auto description = track->description();
auto optCName = description.getCNameForSsrc(ssrc);
if (optCName.has_value()) {
return copyAndReturn(optCName.value(), cname, cnameSize);
} else {
return 0;
}
});
}
int rtcGetSsrcsForType(const char * mediaType, const char * sdp, uint32_t * buffer, int bufferSize) {
return wrap([&] {
auto type = lowercased(string(mediaType));
auto oldSDP = string(sdp);
auto description = Description(oldSDP, "unspec");
auto mediaCount = description.mediaCount();
for (unsigned int i = 0; i < mediaCount; i++) {
if (std::holds_alternative<Description::Media *>(description.media(i))) {
auto media = std::get<Description::Media *>(description.media(i));
auto currentMediaType = lowercased(media->type());
if (currentMediaType == type) {
auto ssrcs = media->getSSRCs();
return copyAndReturn(ssrcs, buffer, bufferSize);
}
}
}
return 0;
});
}
int rtcSetSsrcForType(const char * mediaType, const char * sdp, char * buffer, const int bufferSize,
rtcSsrcForTypeInit * init) {
return wrap([&] {
auto type = lowercased(string(mediaType));
auto prevSDP = string(sdp);
auto description = Description(prevSDP, "unspec");
auto mediaCount = description.mediaCount();
for (unsigned int i = 0; i < mediaCount; i++) {
if (std::holds_alternative<Description::Media *>(description.media(i))) {
auto media = std::get<Description::Media *>(description.media(i));
auto currentMediaType = lowercased(media->type());
if (currentMediaType == type) {
setSSRC(media, init->ssrc, init->name, init->msid, init->trackId);
break;
}
}
}
return copyAndReturn(string(description), buffer, bufferSize);
});
}
#endif // RTC_ENABLE_MEDIA
#if RTC_ENABLE_WEBSOCKET
@ -1136,6 +1262,23 @@ int rtcSetSctpSettings(const rtcSctpSettings *settings) {
if (settings->delayedSackTimeMs > 0)
s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
else if (settings->delayedSackTimeMs < 0)
s.delayedSackTime = std::chrono::milliseconds(0);
if (settings->minRetransmitTimeoutMs > 0)
s.minRetransmitTimeout = std::chrono::milliseconds(settings->minRetransmitTimeoutMs);
if (settings->maxRetransmitTimeoutMs > 0)
s.maxRetransmitTimeout = std::chrono::milliseconds(settings->maxRetransmitTimeoutMs);
if (settings->initialRetransmitTimeoutMs > 0)
s.initialRetransmitTimeout = std::chrono::milliseconds(settings->initialRetransmitTimeoutMs);
if (settings->maxRetransmitAttempts > 0)
s.maxRetransmitAttempts = settings->maxRetransmitAttempts;
if (settings->heartbeatIntervalMs > 0)
s.heartbeatInterval = std::chrono::milliseconds(settings->heartbeatIntervalMs);
SetSctpSettings(std::move(s));
return RTC_ERR_SUCCESS;

View File

@ -547,8 +547,11 @@ void Description::Entry::parseSdpLine(string_view line) {
mAttributes.emplace_back(line.substr(2));
}
}
std::vector<string>::iterator Description::Entry::beginAttributes() { return mAttributes.begin(); }
std::vector<string>::iterator Description::Entry::endAttributes() { return mAttributes.end(); }
std::vector<string>::iterator
Description::Entry::removeAttribute(std::vector<string>::iterator it) {
return mAttributes.erase(it);
@ -556,10 +559,12 @@ Description::Entry::removeAttribute(std::vector<string>::iterator it) {
void Description::Media::addSSRC(uint32_t ssrc, optional<string> name, optional<string> msid,
optional<string> trackID) {
if (name)
if (name) {
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + *name);
else
mCNameMap.emplace(ssrc, *name);
} else {
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc));
}
if (msid)
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " msid:" + *msid + " " +
@ -568,26 +573,28 @@ void Description::Media::addSSRC(uint32_t ssrc, optional<string> name, optional<
mSsrcs.emplace_back(ssrc);
}
void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, optional<string> name,
optional<string> msid, optional<string> trackID) {
auto it = mAttributes.begin();
while (it != mAttributes.end()) {
if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) {
it = mAttributes.erase(it);
} else
it++;
}
addSSRC(ssrc, std::move(name), std::move(msid), std::move(trackID));
}
void Description::Media::removeSSRC(uint32_t oldSSRC) {
auto it = mAttributes.begin();
while (it != mAttributes.end()) {
if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) {
if (match_prefix(*it, "ssrc:" + std::to_string(oldSSRC)))
it = mAttributes.erase(it);
} else
it++;
else
++it;
}
auto jt = mSsrcs.begin();
while (jt != mSsrcs.end()) {
if (*jt == oldSSRC)
jt = mSsrcs.erase(jt);
else
++jt;
}
}
void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, optional<string> name,
optional<string> msid, optional<string> trackID) {
removeSSRC(oldSSRC);
addSSRC(ssrc, std::move(name), std::move(msid), std::move(trackID));
}
bool Description::Media::hasSSRC(uint32_t ssrc) {
@ -858,7 +865,16 @@ void Description::Media::parseSdpLine(string_view line) {
} else if (key == "rtcp-mux") {
// always added
} else if (key == "ssrc") {
mSsrcs.emplace_back(to_integer<uint32_t>(value));
auto ssrc = to_integer<uint32_t>(value);
if (!hasSSRC(ssrc)) {
mSsrcs.emplace_back(ssrc);
}
auto cnamePos = value.find("cname:");
if (cnamePos != string::npos) {
auto cname = value.substr(cnamePos + 6);
mCNameMap.emplace(ssrc, cname);
}
mAttributes.emplace_back(attr);
} else {
Entry::parseSdpLine(line);
}
@ -875,6 +891,14 @@ void Description::Media::addRTPMap(const Description::Media::RTPMap &map) {
std::vector<uint32_t> Description::Media::getSSRCs() { return mSsrcs; }
optional<string> Description::Media::getCNameForSsrc(uint32_t ssrc) {
auto it = mCNameMap.find(ssrc);
if (it != mCNameMap.end()) {
return it->second;
}
return nullopt;
}
std::map<int, Description::Media::RTPMap>::iterator Description::Media::beginMaps() {
return mRtpMap.begin();
}
@ -910,11 +934,16 @@ int Description::Media::RTPMap::parsePT(string_view view) {
void Description::Media::RTPMap::setMLine(string_view mline) {
size_t p = mline.find(' ');
if (p == string::npos)
throw std::invalid_argument("Invalid m-line");
this->pt = to_integer<int>(mline.substr(0, p));
string_view line = mline.substr(p + 1);
size_t spl = line.find('/');
if (spl == string::npos)
throw std::invalid_argument("Invalid m-line");
this->format = line.substr(0, spl);
line = line.substr(spl + 1);
@ -971,7 +1000,7 @@ string Description::typeToString(Type type) {
} // namespace rtc
std::ostream &operator<<(std::ostream &out, const rtc::Description &description) {
return out << std::string(description);
return out << string(description);
}
std::ostream &operator<<(std::ostream &out, rtc::Description::Type type) {
@ -980,18 +1009,17 @@ std::ostream &operator<<(std::ostream &out, rtc::Description::Type type) {
std::ostream &operator<<(std::ostream &out, rtc::Description::Role role) {
using Role = rtc::Description::Role;
const char *str;
// Used for SDP generation, do not change
switch (role) {
case Role::Active:
str = "active";
out << "active";
break;
case Role::Passive:
str = "passive";
out << "passive";
break;
default:
str = "actpass";
out << "actpass";
break;
}
return out << str;
return out;
}

View File

@ -93,3 +93,31 @@ void Cleanup() { Init::Cleanup(); }
void SetSctpSettings(SctpSettings s) { Init::SetSctpSettings(std::move(s)); }
} // namespace rtc
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level) {
switch (level) {
case rtc::LogLevel::Fatal:
out << "fatal";
break;
case rtc::LogLevel::Error:
out << "error";
break;
case rtc::LogLevel::Warning:
out << "warning";
break;
case rtc::LogLevel::Info:
out << "info";
break;
case rtc::LogLevel::Debug:
out << "debug";
break;
case rtc::LogLevel::Verbose:
out << "verbose";
break;
default:
out << "none";
break;
}
return out;
}

View File

@ -28,6 +28,7 @@
#include "sctptransport.hpp"
#include <atomic>
#include <shared_mutex>
namespace rtc::impl {

View File

@ -131,6 +131,11 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
jconfig.turn_servers = k > 0 ? turn_servers : nullptr;
jconfig.turn_servers_count = k;
// Bind address
if (config.bindAddress) {
jconfig.bind_address = config.bindAddress->c_str();
}
// Port range
if (config.portRangeBegin > 1024 ||
(config.portRangeEnd != 0 && config.portRangeEnd != 65535)) {

View File

@ -25,7 +25,9 @@
#include <exception>
#include <iostream>
#include <limits>
#include <shared_mutex>
#include <thread>
#include <unordered_set>
#include <vector>
// RFC 8831: SCTP MUST support performing Path MTU discovery without relying on ICMP or ICMPv6 as
@ -85,21 +87,35 @@ static LogCounter
static LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning,
"Number of SCTP packets received with a bad status");
std::unordered_set<SctpTransport *> SctpTransport::Instances;
std::shared_mutex SctpTransport::InstancesMutex;
class SctpTransport::InstancesSet {
public:
void insert(SctpTransport *instance) {
std::unique_lock lock(mMutex);
mSet.insert(instance);
}
void erase(SctpTransport *instance) {
std::unique_lock lock(mMutex);
mSet.erase(instance);
}
using shared_lock = std::shared_lock<std::shared_mutex>;
optional<shared_lock> lock(SctpTransport *instance) {
shared_lock lock(mMutex);
return mSet.find(instance) != mSet.end() ? std::make_optional(std::move(lock)) : nullopt;
}
private:
std::unordered_set<SctpTransport *> mSet;
std::shared_mutex mMutex;
};
SctpTransport::InstancesSet *SctpTransport::Instances = new InstancesSet;
void SctpTransport::Init() {
usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758)
usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification
usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path
usrsctp_sysctl_set_sctp_rto_min_default(1 * 1000); // ms
usrsctp_sysctl_set_sctp_rto_max_default(10 * 1000); // ms
usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms
usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms
usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
}
void SctpTransport::SetSettings(const SctpSettings &s) {
@ -122,9 +138,33 @@ void SctpTransport::SetSettings(const SctpSettings &s) {
// See https://github.com/paullouisageneau/libdatachannel/issues/354
usrsctp_sysctl_set_sctp_default_cc_module(to_uint32(s.congestionControlModule.value_or(0)));
// Reduce SACK delay to 20ms by default
// Reduce SACK delay to 20ms by default (the recommended default value from RFC 4960 is 200ms)
usrsctp_sysctl_set_sctp_delayed_sack_time_default(
to_uint32(s.delayedSackTime.value_or(20ms).count()));
// RTO settings
// RFC 2988 recommends a 1s min RTO, which is very high, but TCP on Linux has a 200ms min RTO
usrsctp_sysctl_set_sctp_rto_min_default(
to_uint32(s.minRetransmitTimeout.value_or(200ms).count()));
// Set only 10s as max RTO instead of 60s for shorter connection timeout
usrsctp_sysctl_set_sctp_rto_max_default(
to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count()));
usrsctp_sysctl_set_sctp_init_rto_max_default(
to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count()));
// Still set 1s as initial RTO
usrsctp_sysctl_set_sctp_rto_initial_default(
to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count()));
// RTX settings
// 5 retransmissions instead of 8 to shorten the backoff for shorter connection timeout
auto maxRtx = to_uint32(s.maxRetransmitAttempts.value_or(5));
usrsctp_sysctl_set_sctp_init_rtx_max_default(maxRtx);
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(maxRtx);
usrsctp_sysctl_set_sctp_path_rtx_max_default(maxRtx); // single path
// Heartbeat interval
usrsctp_sysctl_set_sctp_heartbeat_interval_default(
to_uint32(s.heartbeatInterval.value_or(10000ms).count()));
}
void SctpTransport::Cleanup() {
@ -143,10 +183,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
PLOG_DEBUG << "Initializing SCTP transport";
usrsctp_register_address(this);
{
std::unique_lock lock(InstancesMutex);
Instances.insert(this);
}
Instances->insert(this);
mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, nullptr, nullptr, 0, nullptr);
if (!mSock)
@ -285,10 +322,7 @@ SctpTransport::~SctpTransport() {
close();
usrsctp_deregister_address(this);
{
std::unique_lock lock(InstancesMutex);
Instances.erase(this);
}
Instances->erase(this);
}
void SctpTransport::start() {
@ -848,11 +882,8 @@ optional<milliseconds> SctpTransport::rtt() {
void SctpTransport::UpcallCallback(struct socket *, void *arg, int /* flags */) {
auto *transport = static_cast<SctpTransport *>(arg);
std::shared_lock lock(InstancesMutex);
if (Instances.find(transport) == Instances.end())
return;
transport->handleUpcall();
if (auto lock = Instances->lock(transport))
transport->handleUpcall();
}
int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) {
@ -860,11 +891,10 @@ int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos,
// Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket
// https://github.com/sctplab/usrsctp/issues/405
std::shared_lock lock(InstancesMutex);
if (Instances.find(transport) == Instances.end())
if (auto lock = Instances->lock(transport))
return transport->handleWrite(static_cast<byte *>(data), len, tos, set_df);
else
return -1;
return transport->handleWrite(static_cast<byte *>(data), len, tos, set_df);
}
} // namespace rtc::impl

View File

@ -29,8 +29,6 @@
#include <functional>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <unordered_set>
#include "usrsctp.h"
@ -120,8 +118,8 @@ private:
static void UpcallCallback(struct socket *sock, void *arg, int flags);
static int WriteCallback(void *sctp_ptr, void *data, size_t len, uint8_t tos, uint8_t set_df);
static std::unordered_set<SctpTransport *> Instances;
static std::shared_mutex InstancesMutex;
class InstancesSet;
static InstancesSet *Instances;
};
} // namespace rtc::impl