Merge branch 'master' into uwp-examples

This commit is contained in:
Paul-Louis Ageneau
2021-03-23 21:30:05 +01:00
committed by GitHub
6 changed files with 52 additions and 48 deletions

View File

@ -16,21 +16,22 @@ The library implements the following communication protocols:
The WebRTC stack has been tested to be compatible with Firefox and Chromium. The WebRTC stack has been tested to be compatible with Firefox and Chromium.
Protocol stack: Protocol stack:
- SCTP-based Data Channels ([draft-ietf-rtcweb-data-channel-13](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13)) - SCTP-based Data Channels ([RFC8831](https://tools.ietf.org/html/rfc8831))
- SRTP-based Media Transport ([draft-ietf-rtcweb-rtp-usage-26](https://tools.ietf.org/html/draft-ietf-rtcweb-rtp-usage-26)) - SRTP-based Media Transport ([RFC8834](https://tools.ietf.org/html/rfc8834))
- DTLS/UDP ([RFC7350](https://tools.ietf.org/html/rfc7350) and [RFC8261](https://tools.ietf.org/html/rfc8261)) - DTLS/UDP ([RFC7350](https://tools.ietf.org/html/rfc7350) and [RFC8261](https://tools.ietf.org/html/rfc8261))
- ICE ([RFC8445](https://tools.ietf.org/html/rfc8445)) with STUN ([RFC8489](https://tools.ietf.org/html/rfc8489)) and its extension TURN ([RFC8656](https://tools.ietf.org/html/rfc8656)) - ICE ([RFC8445](https://tools.ietf.org/html/rfc8445)) with STUN ([RFC8489](https://tools.ietf.org/html/rfc8489)) and its extension TURN ([RFC8656](https://tools.ietf.org/html/rfc8656))
Features: Features:
- Full IPv6 support - Full IPv6 support (as mandated by [RFC8835](https://tools.ietf.org/html/rfc8835))
- Trickle ICE ([draft-ietf-ice-trickle-21](https://tools.ietf.org/html/draft-ietf-ice-trickle-21)) - Trickle ICE ([RFC8838](https://tools.ietf.org/html/rfc8838))
- JSEP compatible ([draft-ietf-rtcweb-jsep-26](https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-26)) - JSEP-compatible session establishment with SDP ([RFC8829](https://tools.ietf.org/html/rfc8829))
- Multicast DNS candidates ([draft-ietf-rtcweb-mdns-ice-candidates-04](https://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-04)) - SCTP over DTLS with SDP offer/answer ([RFC8841](https://tools.ietf.org/html/rfc8841))
- DTLS with ECDSA or RSA keys ([RFC8824](https://tools.ietf.org/html/rfc8827)) - DTLS with ECDSA or RSA keys ([RFC8824](https://tools.ietf.org/html/rfc8827))
- SRTP and SRTCP key derivation from DTLS ([RFC5764](https://tools.ietf.org/html/rfc5764)) - SRTP and SRTCP key derivation from DTLS ([RFC5764](https://tools.ietf.org/html/rfc5764))
- Multicast DNS candidates ([draft-ietf-rtcweb-mdns-ice-candidates-04](https://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-04))
- Differentiated Services QoS ([draft-ietf-tsvwg-rtcweb-qos-18](https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18)) - Differentiated Services QoS ([draft-ietf-tsvwg-rtcweb-qos-18](https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18))
Note only SDP BUNDLE mode is supported for media multiplexing ([draft-ietf-mmusic-sdp-bundle-negotiation-54](https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54)). The behavior is equivalent to the JSEP bundle-only policy: the library always negociates one unique network component, where SRTP media streams are multiplexed with SRTCP control packets ([RFC5761](https://tools.ietf.org/html/rfc5761)) and SCTP/DTLS data traffic ([RFC5764](https://tools.ietf.org/html/rfc5764)). Note only SDP BUNDLE mode is supported for media multiplexing ([RFC8843](https://tools.ietf.org/html/rfc8843)). The behavior is equivalent to the JSEP bundle-only policy: the library always negociates one unique network component, where SRTP media streams are multiplexed with SRTCP control packets ([RFC5761](https://tools.ietf.org/html/rfc5761)) and SCTP/DTLS data traffic ([RFC5764](https://tools.ietf.org/html/rfc5764)).
### WebSocket ### WebSocket
@ -99,12 +100,12 @@ MY_ON_RECV_CANDIDATE_FROM_REMOTE([&pc](string candidate, string mid) {
### Observe the PeerConnection state ### Observe the PeerConnection state
```cpp ```cpp
pc.onStateChange([](PeerConnection::State state) { pc.onStateChange([](rtc::PeerConnection::State state) {
cout << "State: " << state << endl; std::cout << "State: " << state << std::endl;
}); });
pc.onGatheringStateChange([](PeerConnection::GatheringState state) { pc.onGatheringStateChange([](rtc::PeerConnection::GatheringState state) {
cout << "Gathering state: " << state << endl; std::cout << "Gathering state: " << state << std::endl;
}); });
``` ```
@ -114,12 +115,12 @@ pc.onGatheringStateChange([](PeerConnection::GatheringState state) {
auto dc = pc.createDataChannel("test"); auto dc = pc.createDataChannel("test");
dc->onOpen([]() { dc->onOpen([]() {
cout << "Open" << endl; std::cout << "Open" << std::endl;
}); });
dc->onMessage([](variant<binary, string> message) { dc->onMessage([](std::variant<binary, string> message) {
if (holds_alternative<string>(message)) { if (std::holds_alternative<string>(message)) {
cout << "Received: " << get<string>(message) << endl; std::cout << "Received: " << get<string>(message) << std::endl;
} }
}); });
``` ```
@ -127,8 +128,8 @@ dc->onMessage([](variant<binary, string> message) {
### Receive a DataChannel ### Receive a DataChannel
```cpp ```cpp
shared_ptr<rtc::DataChannel> dc; std::shared_ptr<rtc::DataChannel> dc;
pc.onDataChannel([&dc](shared_ptr<rtc::DataChannel> incoming) { pc.onDataChannel([&dc](std::shared_ptr<rtc::DataChannel> incoming) {
dc = incoming; dc = incoming;
dc->send("Hello world!"); dc->send("Hello world!");
}); });
@ -140,12 +141,12 @@ pc.onDataChannel([&dc](shared_ptr<rtc::DataChannel> incoming) {
rtc::WebSocket ws; rtc::WebSocket ws;
ws.onOpen([]() { ws.onOpen([]() {
cout << "WebSocket open" << endl; std::cout << "WebSocket open" << std::endl;
}); });
ws.onMessage([](variant<binary, string> message) { ws.onMessage([](std::variant<binary, string> message) {
if (holds_alternative<string>(message)) { if (std::holds_alternative<string>(message)) {
cout << "WebSocket received: " << get<string>(message) << endl; std::cout << "WebSocket received: " << std::get<string>(message) << endl;
} }
}); });

View File

@ -28,7 +28,7 @@ FileParser::FileParser(string directory, string extension, uint32_t samplesPerSe
} }
void FileParser::start() { void FileParser::start() {
sampleTime_us = -sampleDuration_us; sampleTime_us = std::numeric_limits<uint64_t>::max() - sampleDuration_us + 1;
loadNextSample(); loadNextSample();
} }

View File

@ -243,9 +243,8 @@ string Description::generateSdp(string_view eol) const {
sdp << "s=-" << eol; sdp << "s=-" << eol;
sdp << "t=0 0" << eol; sdp << "t=0 0" << eol;
// Bundle // Bundle (RFC8843 Negotiating Media Multiplexing Using the Session Description Protocol)
// see Negotiating Media Multiplexing Using the Session Description Protocol // https://tools.ietf.org/html/rfc8843
// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54
sdp << "a=group:BUNDLE"; sdp << "a=group:BUNDLE";
for (const auto &entry : mEntries) for (const auto &entry : mEntries)
sdp << ' ' << entry->mid(); sdp << ' ' << entry->mid();

View File

@ -36,8 +36,8 @@ using std::chrono::milliseconds;
namespace rtc::impl { namespace rtc::impl {
// Messages for the DataChannel establishment protocol // Messages for the DataChannel establishment protocol (RFC 8832)
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09 // See https://tools.ietf.org/html/rfc8832
enum MessageType : uint8_t { enum MessageType : uint8_t {
MESSAGE_OPEN_REQUEST = 0x00, MESSAGE_OPEN_REQUEST = 0x00,

View File

@ -541,9 +541,11 @@ shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(Description::Role rol
if (stream == 65535) if (stream == 65535)
throw std::invalid_argument("Invalid DataChannel id"); throw std::invalid_argument("Invalid DataChannel id");
} else { } else {
// The active side must use streams with even identifiers, whereas the passive side must use // RFC 8832: The peer that initiates opening a data channel selects a stream identifier for
// streams with odd identifiers. // which the corresponding incoming and outgoing streams are unused. If the side is acting
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09#section-6 // as the DTLS client, it MUST choose an even stream identifier; if the side is acting as
// the DTLS server, it MUST choose an odd one.
// See https://tools.ietf.org/html/rfc8832#section-6
stream = (role == Description::Role::Active) ? 0 : 1; stream = (role == Description::Role::Active) ? 0 : 1;
while (mDataChannels.find(stream) != mDataChannels.end()) { while (mDataChannels.find(stream) != mDataChannels.end()) {
if (stream >= 65535 - 2) if (stream >= 65535 - 2)

View File

@ -27,10 +27,9 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
// The IETF draft says: // RFC 8831: SCTP MUST support performing Path MTU discovery without relying on ICMP or ICMPv6 as
// SCTP MUST support performing Path MTU discovery without relying on ICMP or ICMPv6 as specified in // specified in [RFC4821] by using probing messages specified in [RFC4820].
// [RFC4821] using probing messages specified in [RFC4820]. // See https://tools.ietf.org/html/rfc8831#section-5
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-5
// //
// However, usrsctp does not implement Path MTU discovery, so we need to disable it for now. // However, usrsctp does not implement Path MTU discovery, so we need to disable it for now.
// See https://github.com/sctplab/usrsctp/issues/205 // See https://github.com/sctplab/usrsctp/issues/205
@ -101,9 +100,8 @@ void SctpTransport::Cleanup() {
std::this_thread::sleep_for(100ms); std::this_thread::sleep_for(100ms);
} }
SctpTransport::SctpTransport(shared_ptr<Transport> lower, uint16_t port, SctpTransport::SctpTransport(shared_ptr<Transport> lower, uint16_t port, optional<size_t> mtu,
optional<size_t> mtu, message_callback recvCallback, message_callback recvCallback, amount_callback bufferedAmountCallback,
amount_callback bufferedAmountCallback,
state_callback stateChangeCallback) state_callback stateChangeCallback)
: Transport(lower, std::move(stateChangeCallback)), mPort(port), : Transport(lower, std::move(stateChangeCallback)), mPort(port),
mSendQueue(0, message_size_func), mBufferedAmountCallback(std::move(bufferedAmountCallback)) { mSendQueue(0, message_size_func), mBufferedAmountCallback(std::move(bufferedAmountCallback)) {
@ -161,8 +159,9 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, uint16_t port,
throw std::runtime_error("Could not subscribe to event SCTP_STREAM_RESET_EVENT, errno=" + throw std::runtime_error("Could not subscribe to event SCTP_STREAM_RESET_EVENT, errno=" +
std::to_string(errno)); std::to_string(errno));
// The sender SHOULD disable the Nagle algorithm (see RFC1122) to minimize the latency. // RFC 8831 6.6. Transferring User Data on a Data Channel
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6 // The sender SHOULD disable the Nagle algorithm (see [RFC1122) to minimize the latency
// See https://tools.ietf.org/html/rfc8831#section-6.6
int nodelay = 1; int nodelay = 1;
if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay))) if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)))
throw std::runtime_error("Could not set socket option SCTP_NODELAY, errno=" + throw std::runtime_error("Could not set socket option SCTP_NODELAY, errno=" +
@ -203,9 +202,10 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, uint16_t port,
throw std::runtime_error("Could not set socket option SCTP_PEER_ADDR_PARAMS, errno=" + throw std::runtime_error("Could not set socket option SCTP_PEER_ADDR_PARAMS, errno=" +
std::to_string(errno)); std::to_string(errno));
// The IETF draft recommends the number of streams negotiated during SCTP association to be // RFC 8831 6.2. SCTP Association Management
// 65535. // The number of streams negotiated during SCTP association setup SHOULD be 65535, which is the
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.2 // maximum number of streams that can be negotiated during the association setup.
// See https://tools.ietf.org/html/rfc8831#section-6.2
struct sctp_initmsg sinit = {}; struct sctp_initmsg sinit = {};
sinit.sinit_num_ostreams = 65535; sinit.sinit_num_ostreams = 65535;
sinit.sinit_max_instreams = 65535; sinit.sinit_max_instreams = 65535;
@ -213,7 +213,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, uint16_t port,
throw std::runtime_error("Could not set socket option SCTP_INITMSG, errno=" + throw std::runtime_error("Could not set socket option SCTP_INITMSG, errno=" +
std::to_string(errno)); std::to_string(errno));
// Prevent fragmented interleave of messages (i.e. level 0), see RFC 6458 8.1.20. // Prevent fragmented interleave of messages (i.e. level 0), see RFC 6458 section 8.1.20.
// Unless the user has set the fragmentation interleave level to 0, notifications // Unless the user has set the fragmentation interleave level to 0, notifications
// may also be interleaved with partially delivered messages. // may also be interleaved with partially delivered messages.
int level = 0; int level = 0;
@ -293,9 +293,9 @@ void SctpTransport::connect() {
if (usrsctp_bind(mSock, reinterpret_cast<struct sockaddr *>(&sconn), sizeof(sconn))) if (usrsctp_bind(mSock, reinterpret_cast<struct sockaddr *>(&sconn), sizeof(sconn)))
throw std::runtime_error("Could not bind usrsctp socket, errno=" + std::to_string(errno)); throw std::runtime_error("Could not bind usrsctp socket, errno=" + std::to_string(errno));
// According to the IETF draft, both endpoints must initiate the SCTP association, in a // According to RFC 8841, both endpoints must initiate the SCTP association, in a
// simultaneous-open manner, irrelevent to the SDP setup role. // simultaneous-open manner, irrelevent to the SDP setup role.
// See https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-9.3 // See https://tools.ietf.org/html/rfc8841#section-9.3
int ret = usrsctp_connect(mSock, reinterpret_cast<struct sockaddr *>(&sconn), sizeof(sconn)); int ret = usrsctp_connect(mSock, reinterpret_cast<struct sockaddr *>(&sconn), sizeof(sconn));
if (ret && errno != EINPROGRESS) if (ret && errno != EINPROGRESS)
throw std::runtime_error("Connection attempt failed, errno=" + std::to_string(errno)); throw std::runtime_error("Connection attempt failed, errno=" + std::to_string(errno));
@ -632,9 +632,11 @@ int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, uint8_t
void SctpTransport::processData(binary &&data, uint16_t sid, PayloadId ppid) { void SctpTransport::processData(binary &&data, uint16_t sid, PayloadId ppid) {
PLOG_VERBOSE << "Process data, size=" << data.size(); PLOG_VERBOSE << "Process data, size=" << data.size();
// The usage of the PPIDs "WebRTC String Partial" and "WebRTC Binary Partial" is deprecated. // RFC 8831: The usage of the PPIDs "WebRTC String Partial" and "WebRTC Binary Partial" is
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6 // deprecated. They were used for a PPID-based fragmentation and reassembly of user messages
// We handle them at reception for compatibility reasons but should never send them. // belonging to reliable and ordered data channels.
// See https://tools.ietf.org/html/rfc8831#section-6.6
// We handle those PPIDs at reception for compatibility reasons but shall never send them.
switch (ppid) { switch (ppid) {
case PPID_CONTROL: case PPID_CONTROL:
recv(make_message(std::move(data), Message::Control, sid)); recv(make_message(std::move(data), Message::Control, sid));