Browse Source

Merge remote-tracking branch 'paulgit/master' into newdesc

Staz M 4 years ago
parent
commit
f008b5b447

+ 6 - 14
CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.7)
 cmake_minimum_required(VERSION 3.7)
 project(libdatachannel
 project(libdatachannel
-	VERSION 0.10.1
+	VERSION 0.10.3
 	LANGUAGES CXX)
 	LANGUAGES CXX)
 set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
 set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
 
 
@@ -36,7 +36,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
 
 
 if(WIN32)
 if(WIN32)
 	add_definitions(-DWIN32_LEAN_AND_MEAN)
 	add_definitions(-DWIN32_LEAN_AND_MEAN)
-	if (MSVC)
+	if(MSVC)
 		add_definitions(-DNOMINMAX)
 		add_definitions(-DNOMINMAX)
 		add_definitions(-D_CRT_SECURE_NO_WARNINGS)
 		add_definitions(-D_CRT_SECURE_NO_WARNINGS)
 		add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
 		add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
@@ -163,8 +163,8 @@ target_link_libraries(datachannel-static PUBLIC Threads::Threads plog::plog)
 target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp)
 target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp)
 
 
 if(WIN32)
 if(WIN32)
-	target_link_libraries(datachannel PRIVATE ws2_32) # winsock2
-	target_link_libraries(datachannel-static PRIVATE ws2_32) # winsock2
+	target_link_libraries(datachannel PUBLIC ws2_32) # winsock2
+	target_link_libraries(datachannel-static PUBLIC ws2_32) # winsock2
 endif()
 endif()
 
 
 if(NO_MEDIA)
 if(NO_MEDIA)
@@ -272,11 +272,7 @@ if(NOT NO_TESTS)
 		set_target_properties(datachannel-tests PROPERTIES OUTPUT_NAME tests)
 		set_target_properties(datachannel-tests PROPERTIES OUTPUT_NAME tests)
 	endif()
 	endif()
 	target_include_directories(datachannel-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
 	target_include_directories(datachannel-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
-	if(WIN32)
-		target_link_libraries(datachannel-tests datachannel-static) # DLL exports only the C API
-	else()
-		target_link_libraries(datachannel-tests datachannel)
-	endif()
+	target_link_libraries(datachannel-tests datachannel)
 
 
 	# Benchmark
 	# Benchmark
 	add_executable(datachannel-benchmark test/benchmark.cpp)
 	add_executable(datachannel-benchmark test/benchmark.cpp)
@@ -288,11 +284,7 @@ if(NOT NO_TESTS)
 	endif()
 	endif()
 	target_compile_definitions(datachannel-benchmark PRIVATE BENCHMARK_MAIN=1)
 	target_compile_definitions(datachannel-benchmark PRIVATE BENCHMARK_MAIN=1)
 	target_include_directories(datachannel-benchmark PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
 	target_include_directories(datachannel-benchmark PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
-	if(WIN32)
-		target_link_libraries(datachannel-benchmark datachannel-static) # DLL exports only the C API
-	else()
-		target_link_libraries(datachannel-benchmark datachannel)
-	endif()
+	target_link_libraries(datachannel-benchmark datachannel)
 endif()
 endif()
 
 
 # Examples
 # Examples

+ 2 - 1
README.md

@@ -27,8 +27,9 @@ Features:
 - Full IPv6 support
 - Full IPv6 support
 - Trickle ICE ([draft-ietf-ice-trickle-21](https://tools.ietf.org/html/draft-ietf-ice-trickle-21))
 - Trickle ICE ([draft-ietf-ice-trickle-21](https://tools.ietf.org/html/draft-ietf-ice-trickle-21))
 - JSEP compatible ([draft-ietf-rtcweb-jsep-26](https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-26))
 - JSEP compatible ([draft-ietf-rtcweb-jsep-26](https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-26))
-- 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))
 - Multicast DNS candidates ([draft-ietf-rtcweb-mdns-ice-candidates-04](https://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-04))
+- SRTP and SRTCP key derivation from DTLS ([RFC5764](https://tools.ietf.org/html/rfc5764))
+- Differentiated Services QoS ([draft-ietf-tsvwg-rtcweb-qos-18](https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18))
 - TURN relaying ([RFC5766](https://tools.ietf.org/html/rfc5766)) with [libnice](https://github.com/libnice/libnice) as ICE backend
 - TURN relaying ([RFC5766](https://tools.ietf.org/html/rfc5766)) with [libnice](https://github.com/libnice/libnice) as ICE backend
 
 
 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 ([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)).

+ 1 - 1
deps/libjuice

@@ -1 +1 @@
-Subproject commit 7afe3940dd73fde781333af556310f8a499cff40
+Subproject commit ea96b8863501f6c4cc8e33ac1eca05b54e428d30

+ 1 - 1
deps/libsrtp

@@ -1 +1 @@
-Subproject commit d02d21111e379c297e93a9033d7b653135f732ee
+Subproject commit f379f4841228ee82932b56509e73adaf6552ce6e

+ 1 - 6
examples/client/CMakeLists.txt

@@ -9,14 +9,9 @@ target_compile_definitions(datachannel-client PUBLIC STATIC_GETOPT)
 else()
 else()
 add_executable(datachannel-client main.cpp parse_cl.cpp parse_cl.h)
 add_executable(datachannel-client main.cpp parse_cl.cpp parse_cl.h)
 endif()
 endif()
+
 set_target_properties(datachannel-client PROPERTIES
 set_target_properties(datachannel-client PROPERTIES
 	CXX_STANDARD 17
 	CXX_STANDARD 17
 	OUTPUT_NAME client)
 	OUTPUT_NAME client)
-
-if(WIN32)
-	target_link_libraries(datachannel-client datachannel-static) # DLL exports only the C API
-else()
-	target_link_libraries(datachannel-client datachannel)
-endif()
 target_link_libraries(datachannel-client datachannel nlohmann_json)
 target_link_libraries(datachannel-client datachannel nlohmann_json)
 
 

+ 2 - 10
examples/copy-paste/CMakeLists.txt

@@ -4,19 +4,11 @@ add_executable(datachannel-copy-paste-offerer offerer.cpp)
 set_target_properties(datachannel-copy-paste-offerer PROPERTIES
 set_target_properties(datachannel-copy-paste-offerer PROPERTIES
 	CXX_STANDARD 17
 	CXX_STANDARD 17
 	OUTPUT_NAME offerer)
 	OUTPUT_NAME offerer)
-if(WIN32)
-	target_link_libraries(datachannel-copy-paste-offerer datachannel-static) # DLL exports only the C API
-else()
-	target_link_libraries(datachannel-copy-paste-offerer datachannel)
-endif()
+target_link_libraries(datachannel-copy-paste-offerer datachannel)
 
 
 add_executable(datachannel-copy-paste-answerer answerer.cpp)
 add_executable(datachannel-copy-paste-answerer answerer.cpp)
 set_target_properties(datachannel-copy-paste-answerer PROPERTIES
 set_target_properties(datachannel-copy-paste-answerer PROPERTIES
 	CXX_STANDARD 17
 	CXX_STANDARD 17
 	OUTPUT_NAME answerer)
 	OUTPUT_NAME answerer)
-if(WIN32)
-	target_link_libraries(datachannel-copy-paste-answerer datachannel-static) # DLL exports only the C API
-else()
-	target_link_libraries(datachannel-copy-paste-answerer datachannel)
-endif()
+target_link_libraries(datachannel-copy-paste-answerer datachannel)
 
 

+ 1 - 7
examples/media/CMakeLists.txt

@@ -4,11 +4,5 @@ add_executable(datachannel-media main.cpp)
 set_target_properties(datachannel-media PROPERTIES
 set_target_properties(datachannel-media PROPERTIES
         CXX_STANDARD 17
         CXX_STANDARD 17
         OUTPUT_NAME media)
         OUTPUT_NAME media)
+target_link_libraries(datachannel-media datachannel nlohmann_json)
 
 
-if(WIN32)
-    target_link_libraries(datachannel-media datachannel-static) # DLL exports only the C API
-else()
-    target_link_libraries(datachannel-media datachannel)
-endif()
-
-target_link_libraries(datachannel-media datachannel nlohmann_json)

+ 0 - 7
examples/sfu-media/CMakeLists.txt

@@ -4,12 +4,5 @@ add_executable(datachannel-sfu-media main.cpp)
 set_target_properties(datachannel-sfu-media PROPERTIES
 set_target_properties(datachannel-sfu-media PROPERTIES
 		CXX_STANDARD 17
 		CXX_STANDARD 17
 		OUTPUT_NAME sfu-media)
 		OUTPUT_NAME sfu-media)
-
-if(WIN32)
-	target_link_libraries(datachannel-sfu-media datachannel-static) # DLL exports only the C API
-else()
-	target_link_libraries(datachannel-sfu-media datachannel)
-endif()
-
 target_link_libraries(datachannel-sfu-media datachannel nlohmann_json)
 target_link_libraries(datachannel-sfu-media datachannel nlohmann_json)
 
 

+ 4 - 4
include/rtc/candidate.hpp

@@ -25,7 +25,7 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-class Candidate {
+class RTC_CPP_EXPORT Candidate {
 public:
 public:
 	enum class Family { Unresolved, Ipv4, Ipv6 };
 	enum class Family { Unresolved, Ipv4, Ipv6 };
 	enum class Type { Unknown, Host, ServerReflexive, PeerReflexive, Relayed };
 	enum class Type { Unknown, Host, ServerReflexive, PeerReflexive, Relayed };
@@ -76,8 +76,8 @@ private:
 
 
 } // namespace rtc
 } // namespace rtc
 
 
-std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate);
-std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type);
-std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType);
 
 
 #endif
 #endif

+ 1 - 1
include/rtc/channel.hpp

@@ -28,7 +28,7 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-class Channel {
+class RTC_CPP_EXPORT Channel {
 public:
 public:
 	Channel() = default;
 	Channel() = default;
 	virtual ~Channel() = default;
 	virtual ~Channel() = default;

+ 3 - 3
include/rtc/configuration.hpp

@@ -26,7 +26,7 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-struct IceServer {
+struct RTC_CPP_EXPORT IceServer {
 	enum class Type { Stun, Turn };
 	enum class Type { Stun, Turn };
 	enum class RelayType { TurnUdp, TurnTcp, TurnTls };
 	enum class RelayType { TurnUdp, TurnTcp, TurnTls };
 
 
@@ -51,7 +51,7 @@ struct IceServer {
 	RelayType relayType;
 	RelayType relayType;
 };
 };
 
 
-struct ProxyServer {
+struct RTC_CPP_EXPORT ProxyServer {
 	enum class Type { None = 0, Socks5, Http, Last = Http };
 	enum class Type { None = 0, Socks5, Http, Last = Http };
 
 
 	ProxyServer(Type type_, string ip_, uint16_t port_, string username_ = "",
 	ProxyServer(Type type_, string ip_, uint16_t port_, string username_ = "",
@@ -64,7 +64,7 @@ struct ProxyServer {
 	string password;
 	string password;
 };
 };
 
 
-struct Configuration {
+struct RTC_CPP_EXPORT Configuration {
 	std::vector<IceServer> iceServers;
 	std::vector<IceServer> iceServers;
 	std::optional<ProxyServer> proxyServer;
 	std::optional<ProxyServer> proxyServer;
 	bool enableIceTcp = false;
 	bool enableIceTcp = false;

+ 2 - 2
include/rtc/datachannel.hpp

@@ -36,7 +36,7 @@ namespace rtc {
 class SctpTransport;
 class SctpTransport;
 class PeerConnection;
 class PeerConnection;
 
 
-class DataChannel : public std::enable_shared_from_this<DataChannel>, public Channel {
+class RTC_CPP_EXPORT DataChannel : public std::enable_shared_from_this<DataChannel>, public Channel {
 public:
 public:
 	DataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label, string protocol,
 	DataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label, string protocol,
 	            Reliability reliability);
 	            Reliability reliability);
@@ -87,7 +87,7 @@ private:
 	friend class PeerConnection;
 	friend class PeerConnection;
 };
 };
 
 
-class NegociatedDataChannel final : public DataChannel {
+class RTC_CPP_EXPORT NegociatedDataChannel final : public DataChannel {
 public:
 public:
 	NegociatedDataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label,
 	NegociatedDataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label,
 	                      string protocol, Reliability reliability);
 	                      string protocol, Reliability reliability);

+ 9 - 9
include/rtc/description.hpp

@@ -32,7 +32,7 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-class Description {
+class RTC_CPP_EXPORT Description {
 public:
 public:
 	enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
 	enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
 	enum class Role { ActPass, Passive, Active };
 	enum class Role { ActPass, Passive, Active };
@@ -63,7 +63,7 @@ public:
 	string generateSdp(string_view eol) const;
 	string generateSdp(string_view eol) const;
 	string generateApplicationSdp(string_view eol) const;
 	string generateApplicationSdp(string_view eol) const;
 
 
-	class Entry {
+	class RTC_CPP_EXPORT Entry {
 	public:
 	public:
 		virtual ~Entry() = default;
 		virtual ~Entry() = default;
 
 
@@ -95,7 +95,7 @@ public:
 		Direction mDirection;
 		Direction mDirection;
 	};
 	};
 
 
-	struct Application : public Entry {
+	struct RTC_CPP_EXPORT Application : public Entry {
 	public:
 	public:
 		Application(string mid = "data");
 		Application(string mid = "data");
 		virtual ~Application() = default;
 		virtual ~Application() = default;
@@ -120,7 +120,7 @@ public:
 	};
 	};
 
 
 	// Media (non-data)
 	// Media (non-data)
-	class Media : public Entry {
+	class RTC_CPP_EXPORT Media : public Entry {
 	public:
 	public:
 		Media(const string &sdp);
 		Media(const string &sdp);
 		Media(const string &mline, string mid, Direction dir = Direction::SendOnly);
 		Media(const string &mline, string mid, Direction dir = Direction::SendOnly);
@@ -186,7 +186,7 @@ public:
         void removeSSRC(uint32_t oldSSRC);
         void removeSSRC(uint32_t oldSSRC);
     };
     };
 
 
-	class Audio : public Media {
+	class RTC_CPP_EXPORT Audio : public Media {
 	public:
 	public:
 		Audio(string mid = "audio", Direction dir = Direction::SendOnly);
 		Audio(string mid = "audio", Direction dir = Direction::SendOnly);
 
 
@@ -196,7 +196,7 @@ public:
         void addRTXCodec(unsigned int payloadType, unsigned int originalPayloadType, unsigned int clockRate);
         void addRTXCodec(unsigned int payloadType, unsigned int originalPayloadType, unsigned int clockRate);
     };
     };
 
 
-	class Video : public Media {
+	class RTC_CPP_EXPORT Video : public Media {
 	public:
 	public:
 		Video(string mid = "video", Direction dir = Direction::SendOnly);
 		Video(string mid = "video", Direction dir = Direction::SendOnly);
 
 
@@ -250,8 +250,8 @@ private:
 
 
 } // namespace rtc
 } // namespace rtc
 
 
-std::ostream &operator<<(std::ostream &out, const rtc::Description &description);
-std::ostream &operator<<(std::ostream &out, rtc::Description::Type type);
-std::ostream &operator<<(std::ostream &out, rtc::Description::Role role);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Description &description);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Type type);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Role role);
 
 
 #endif
 #endif

+ 6 - 0
include/rtc/include.hpp

@@ -28,9 +28,15 @@
 #endif
 #endif
 
 
 #ifdef _WIN32
 #ifdef _WIN32
+#define RTC_CPP_EXPORT __declspec(dllexport)
 #ifndef _WIN32_WINNT
 #ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x0602 // Windows 8
 #define _WIN32_WINNT 0x0602 // Windows 8
 #endif
 #endif
+#ifdef _MSC_VER
+#pragma warning(disable:4251) // disable "X needs to have dll-interface..."
+#endif
+#else
+#define RTC_CPP_EXPORT
 #endif
 #endif
 
 
 #include "log.hpp"
 #include "log.hpp"

+ 1 - 1
include/rtc/init.hpp

@@ -27,7 +27,7 @@ namespace rtc {
 
 
 using init_token = std::shared_ptr<void>;
 using init_token = std::shared_ptr<void>;
 
 
-class Init {
+class RTC_CPP_EXPORT Init {
 public:
 public:
 	static init_token Token();
 	static init_token Token();
 	static void Preload();
 	static void Preload();

+ 4 - 2
include/rtc/log.hpp

@@ -35,6 +35,8 @@
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 #endif
 
 
+#include "include.hpp"
+
 namespace rtc {
 namespace rtc {
 
 
 enum class LogLevel { // Don't change, it must match plog severity
 enum class LogLevel { // Don't change, it must match plog severity
@@ -47,8 +49,8 @@ enum class LogLevel { // Don't change, it must match plog severity
 	Verbose = 6
 	Verbose = 6
 };
 };
 
 
-void InitLogger(LogLevel level);
-void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
+RTC_CPP_EXPORT void InitLogger(LogLevel level);
+RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
 } // namespace rtc
 } // namespace rtc
 
 
 #endif
 #endif

+ 3 - 2
include/rtc/message.hpp

@@ -29,7 +29,7 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-struct Message : binary {
+struct RTC_CPP_EXPORT Message : binary {
 	enum Type { Binary, String, Control, Reset };
 	enum Type { Binary, String, Control, Reset };
 
 
 	Message(const Message &message) = default;
 	Message(const Message &message) = default;
@@ -42,7 +42,8 @@ struct Message : binary {
 	Message(binary &&data, Type type_ = Binary) : binary(std::move(data)), type(type_) {}
 	Message(binary &&data, Type type_ = Binary) : binary(std::move(data)), type(type_) {}
 
 
 	Type type;
 	Type type;
-	unsigned int stream = 0;
+	unsigned int stream = 0; // Stream id (SCTP stream or SSRC)
+	unsigned int dscp = 0;   // Differentiated Services Code Point
 	std::shared_ptr<Reliability> reliability;
 	std::shared_ptr<Reliability> reliability;
 };
 };
 
 

+ 5 - 5
include/rtc/peerconnection.hpp

@@ -50,14 +50,14 @@ class SctpTransport;
 using certificate_ptr = std::shared_ptr<Certificate>;
 using certificate_ptr = std::shared_ptr<Certificate>;
 using future_certificate_ptr = std::shared_future<certificate_ptr>;
 using future_certificate_ptr = std::shared_future<certificate_ptr>;
 
 
-struct DataChannelInit {
+struct RTC_CPP_EXPORT DataChannelInit {
 	Reliability reliability = {};
 	Reliability reliability = {};
 	bool negotiated = false;
 	bool negotiated = false;
 	std::optional<uint16_t> id = nullopt;
 	std::optional<uint16_t> id = nullopt;
 	string protocol = "";
 	string protocol = "";
 };
 };
 
 
-class PeerConnection final : public std::enable_shared_from_this<PeerConnection> {
+class RTC_CPP_EXPORT PeerConnection final : public std::enable_shared_from_this<PeerConnection> {
 public:
 public:
 	enum class State : int {
 	enum class State : int {
 		New = RTC_NEW,
 		New = RTC_NEW,
@@ -203,8 +203,8 @@ private:
 
 
 } // namespace rtc
 } // namespace rtc
 
 
-std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::State state);
-std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::GatheringState state);
-std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::SignalingState state);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::State state);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::GatheringState state);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::SignalingState state);
 
 
 #endif
 #endif

+ 2 - 2
include/rtc/rtcp.hpp

@@ -29,7 +29,7 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-class RtcpHandler {
+class RTC_CPP_EXPORT RtcpHandler {
 protected:
 protected:
 	/**
 	/**
 	 * Use this callback when trying to send custom data (such as RTCP) to the client.
 	 * Use this callback when trying to send custom data (such as RTCP) to the client.
@@ -64,7 +64,7 @@ public:
 class Track;
 class Track;
 
 
 // An RtcpSession can be plugged into a Track to handle the whole RTCP session
 // An RtcpSession can be plugged into a Track to handle the whole RTCP session
-class RtcpReceivingSession : public RtcpHandler {
+class RTC_CPP_EXPORT RtcpReceivingSession : public RtcpHandler {
 public:
 public:
 	rtc::message_ptr incoming(rtc::message_ptr ptr) override;
 	rtc::message_ptr incoming(rtc::message_ptr ptr) override;
 	rtc::message_ptr outgoing(rtc::message_ptr ptr) override;
 	rtc::message_ptr outgoing(rtc::message_ptr ptr) override;

+ 19 - 23
include/rtc/rtp.hpp

@@ -20,7 +20,7 @@
 #ifndef RTC_RTP_HPP
 #ifndef RTC_RTP_HPP
 #define RTC_RTP_HPP
 #define RTC_RTP_HPP
 
 
-#include <rtc/log.hpp>
+#include "log.hpp"
 
 
 #include <cmath>
 #include <cmath>
 
 
@@ -75,19 +75,15 @@ public:
 	inline void setPayloadType(uint8_t newPayloadType) {
 	inline void setPayloadType(uint8_t newPayloadType) {
 		_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
 		_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
 	}
 	}
-	inline void setSsrc(uint32_t ssrc) { _ssrc = htonl(ssrc); }
+	inline void setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); }
 
 
 	void setTimestamp(uint32_t i) { _timestamp = htonl(i); }
 	void setTimestamp(uint32_t i) { _timestamp = htonl(i); }
 
 
 	void log() {
 	void log() {
-		PLOG_VERBOSE  << "RTP V: " << (int) version()
-		            << " P: " << (padding() ? "P" : " ")
-		            << " X: " << (extension() ? "X" : " ")
-		            << " CC: "  << (int) csrcCount()
-		            << " M: " << (marker() ? "M" : " ")
-		            << " PT: " << (int) payloadType()
-		            << " SEQNO: " << seqNumber()
-		            << " TS: " << timestamp();
+		PLOG_VERBOSE << "RTP V: " << (int)version() << " P: " << (padding() ? "P" : " ")
+		             << " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount()
+		             << " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType()
+		             << " SEQNO: " << seqNumber() << " TS: " << timestamp();
 	}
 	}
 };
 };
 
 
@@ -103,13 +99,13 @@ private:
 	uint32_t _delaySinceLastReport;
 	uint32_t _delaySinceLastReport;
 
 
 public:
 public:
-	inline void preparePacket(SSRC ssrc, [[maybe_unused]] unsigned int packetsLost,
+	inline void preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost,
 	                          [[maybe_unused]] unsigned int totalPackets, uint16_t highestSeqNo,
 	                          [[maybe_unused]] unsigned int totalPackets, uint16_t highestSeqNo,
 	                          uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP,
 	                          uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP,
 	                          uint64_t lastSR_DELAY) {
 	                          uint64_t lastSR_DELAY) {
 		setSeqNo(highestSeqNo, seqNoCycles);
 		setSeqNo(highestSeqNo, seqNoCycles);
 		setJitter(jitter);
 		setJitter(jitter);
-		setSSRC(ssrc);
+		setSSRC(in_ssrc);
 
 
 		// Middle 32 bits of NTP Timestamp
 		// Middle 32 bits of NTP Timestamp
 		//		  this->lastReport = lastSR_NTP >> 16u;
 		//		  this->lastReport = lastSR_NTP >> 16u;
@@ -120,7 +116,7 @@ public:
 		//		  this->delaySinceLastReport = lastSR_DELAY;
 		//		  this->delaySinceLastReport = lastSR_DELAY;
 	}
 	}
 
 
-	inline void setSSRC(SSRC ssrc) { this->ssrc = htonl(ssrc); }
+	inline void setSSRC(SSRC in_ssrc) { this->ssrc = htonl(in_ssrc); }
 	inline SSRC getSSRC() const { return ntohl(ssrc); }
 	inline SSRC getSSRC() const { return ntohl(ssrc); }
 
 
 	inline void setPacketsLost([[maybe_unused]] unsigned int packetsLost,
 	inline void setPacketsLost([[maybe_unused]] unsigned int packetsLost,
@@ -199,9 +195,9 @@ public:
 
 
 	inline void log() const {
 	inline void log() const {
 		PLOG_VERBOSE << "RTCP header: "
 		PLOG_VERBOSE << "RTCP header: "
-		          << "version=" << unsigned(version()) << ", padding=" << padding()
-		          << ", reportCount=" << unsigned(reportCount())
-		          << ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
+		             << "version=" << unsigned(version()) << ", padding=" << padding()
+		             << ", reportCount=" << unsigned(reportCount())
+		             << ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
 	}
 	}
 };
 };
 
 
@@ -337,7 +333,7 @@ struct RTCP_REMB {
 		return sizeof(uint32_t) * (1 + header.header.length());
 		return sizeof(uint32_t) * (1 + header.header.length());
 	}
 	}
 
 
-	void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int bitrate) {
+	void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) {
 
 
 		// Report Count becomes the format here.
 		// Report Count becomes the format here.
 		header.header.prepareHeader(206, 15, 0);
 		header.header.prepareHeader(206, 15, 0);
@@ -352,21 +348,21 @@ struct RTCP_REMB {
 		id[2] = 'M';
 		id[2] = 'M';
 		id[3] = 'B';
 		id[3] = 'B';
 
 
-		setBitrate(numSSRC, bitrate);
+		setBitrate(numSSRC, in_bitrate);
 	}
 	}
 
 
-	void setBitrate(unsigned int numSSRC, unsigned int bitrate) {
+	void setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
 		unsigned int exp = 0;
 		unsigned int exp = 0;
-		while (bitrate > pow(2, 18) - 1) {
+		while (in_bitrate > pow(2, 18) - 1) {
 			exp++;
 			exp++;
-			bitrate /= 2;
+			in_bitrate /= 2;
 		}
 		}
 
 
 		// "length" in packet is one less than the number of 32 bit words in the packet.
 		// "length" in packet is one less than the number of 32 bit words in the packet.
 		header.header.setLength(
 		header.header.setLength(
 		    uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
 		    uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
 
 
-		this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | bitrate);
+		this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate);
 	}
 	}
 
 
 	void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); }
 	void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); }
@@ -428,7 +424,7 @@ public:
 
 
 public:
 public:
 	void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
 	void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
-		header.header.prepareHeader(205, 1, 2 + discreteSeqNoCount);
+		header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount));
 		header.setMediaSourceSSRC(ssrc);
 		header.setMediaSourceSSRC(ssrc);
 		header.setPacketSenderSSRC(ssrc);
 		header.setPacketSenderSSRC(ssrc);
 	}
 	}

+ 2 - 2
include/rtc/track.hpp

@@ -35,7 +35,7 @@ namespace rtc {
 class DtlsSrtpTransport;
 class DtlsSrtpTransport;
 #endif
 #endif
 
 
-class Track final : public std::enable_shared_from_this<Track>, public Channel {
+class RTC_CPP_EXPORT Track final : public std::enable_shared_from_this<Track>, public Channel {
 public:
 public:
 	Track(Description::Media description);
 	Track(Description::Media description);
 	~Track() = default;
 	~Track() = default;
@@ -70,8 +70,8 @@ private:
 	std::weak_ptr<DtlsSrtpTransport> mDtlsSrtpTransport;
 	std::weak_ptr<DtlsSrtpTransport> mDtlsSrtpTransport;
 #endif
 #endif
 
 
-	bool outgoing(message_ptr message);
 	void incoming(message_ptr message);
 	void incoming(message_ptr message);
+	bool outgoing(message_ptr message);
 
 
 	Description::Media mMediaDescription;
 	Description::Media mMediaDescription;
 	std::atomic<bool> mIsClosed = false;
 	std::atomic<bool> mIsClosed = false;

+ 1 - 1
include/rtc/websocket.hpp

@@ -38,7 +38,7 @@ class TcpTransport;
 class TlsTransport;
 class TlsTransport;
 class WsTransport;
 class WsTransport;
 
 
-class WebSocket final : public Channel, public std::enable_shared_from_this<WebSocket> {
+class RTC_CPP_EXPORT WebSocket final : public Channel, public std::enable_shared_from_this<WebSocket> {
 public:
 public:
 	enum class State : int {
 	enum class State : int {
 		Connecting = 0,
 		Connecting = 0,

+ 11 - 4
src/dtlssrtptransport.cpp

@@ -130,8 +130,8 @@ bool DtlsSrtpTransport::sendMedia(message_ptr message) {
 				auto ssrc = ((RTP *)message->data())->ssrc();
 				auto ssrc = ((RTP *)message->data())->ssrc();
 				PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
 				PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
 				addSSRC(ssrc);
 				addSSRC(ssrc);
-				if ((err = srtp_protect_rtcp(mSrtpOut, message->data(), &size)))
-					throw std::runtime_error("SRTCP protect error, status=" +
+				if ((err = srtp_protect(mSrtpOut, message->data(), &size)))
+					throw std::runtime_error("SRTP protect error, status=" +
 					                         to_string(static_cast<int>(err)));
 					                         to_string(static_cast<int>(err)));
 			} else
 			} else
 				throw std::runtime_error("SRTP protect error, status=" +
 				throw std::runtime_error("SRTP protect error, status=" +
@@ -141,7 +141,14 @@ bool DtlsSrtpTransport::sendMedia(message_ptr message) {
 	}
 	}
 
 
 	message->resize(size);
 	message->resize(size);
-	return outgoing(message);
+
+	if (message->dscp == 0) { // Track might override the value
+		// Set recommended medium-priority DSCP value
+		// See https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18
+		message->dscp = 36; // AF42: Assured Forwarding class 4, medium drop probability
+	}
+
+	return Transport::outgoing(message); // bypass DTLS DSCP marking
 }
 }
 
 
 void DtlsSrtpTransport::incoming(message_ptr message) {
 void DtlsSrtpTransport::incoming(message_ptr message) {
@@ -217,7 +224,7 @@ void DtlsSrtpTransport::incoming(message_ptr message) {
 					PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
 					PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
 					addSSRC(ssrc);
 					addSSRC(ssrc);
 					if ((err = srtp_unprotect(mSrtpIn, message->data(), &size)))
 					if ((err = srtp_unprotect(mSrtpIn, message->data(), &size)))
-						throw std::runtime_error("SRTCP unprotect error, status=" +
+						throw std::runtime_error("SRTP unprotect error, status=" +
 						                         to_string(static_cast<int>(err)));
 						                         to_string(static_cast<int>(err)));
 				} else
 				} else
 					PLOG_WARNING << "SRTP unprotect error, status=" << err
 					PLOG_WARNING << "SRTP unprotect error, status=" << err

+ 18 - 2
src/dtlstransport.cpp

@@ -53,7 +53,7 @@ DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr cer
                              verifier_callback verifierCallback, state_callback stateChangeCallback)
                              verifier_callback verifierCallback, state_callback stateChangeCallback)
     : Transport(lower, std::move(stateChangeCallback)), mCertificate(certificate),
     : Transport(lower, std::move(stateChangeCallback)), mCertificate(certificate),
       mVerifierCallback(std::move(verifierCallback)),
       mVerifierCallback(std::move(verifierCallback)),
-      mIsClient(lower->role() == Description::Role::Active) {
+      mIsClient(lower->role() == Description::Role::Active), mCurrentDscp(0) {
 
 
 	PLOG_DEBUG << "Initializing DTLS transport (GnuTLS)";
 	PLOG_DEBUG << "Initializing DTLS transport (GnuTLS)";
 
 
@@ -122,6 +122,7 @@ bool DtlsTransport::send(message_ptr message) {
 
 
 	PLOG_VERBOSE << "Send size=" << message->size();
 	PLOG_VERBOSE << "Send size=" << message->size();
 
 
+	mCurrentDscp = message->dscp;
 	ssize_t ret;
 	ssize_t ret;
 	do {
 	do {
 		ret = gnutls_record_send(mSession, message->data(), message->size());
 		ret = gnutls_record_send(mSession, message->data(), message->size());
@@ -143,6 +144,13 @@ void DtlsTransport::incoming(message_ptr message) {
 	mIncomingQueue.push(message);
 	mIncomingQueue.push(message);
 }
 }
 
 
+bool DtlsTransport::outgoing(message_ptr message) {
+	if (message->dscp == 0)
+		message->dscp = mCurrentDscp;
+
+	return Transport::outgoing(std::move(message));
+}
+
 void DtlsTransport::postHandshake() {
 void DtlsTransport::postHandshake() {
 	// Dummy
 	// Dummy
 }
 }
@@ -309,7 +317,7 @@ DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, shared_ptr<Certific
                              verifier_callback verifierCallback, state_callback stateChangeCallback)
                              verifier_callback verifierCallback, state_callback stateChangeCallback)
     : Transport(lower, std::move(stateChangeCallback)), mCertificate(certificate),
     : Transport(lower, std::move(stateChangeCallback)), mCertificate(certificate),
       mVerifierCallback(std::move(verifierCallback)),
       mVerifierCallback(std::move(verifierCallback)),
-      mIsClient(lower->role() == Description::Role::Active) {
+      mIsClient(lower->role() == Description::Role::Active), mCurrentDscp(0) {
 	PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)";
 	PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)";
 
 
 	try {
 	try {
@@ -405,6 +413,7 @@ bool DtlsTransport::send(message_ptr message) {
 
 
 	PLOG_VERBOSE << "Send size=" << message->size();
 	PLOG_VERBOSE << "Send size=" << message->size();
 
 
+	mCurrentDscp = message->dscp;
 	int ret = SSL_write(mSsl, message->data(), int(message->size()));
 	int ret = SSL_write(mSsl, message->data(), int(message->size()));
 	return openssl::check(mSsl, ret);
 	return openssl::check(mSsl, ret);
 }
 }
@@ -419,6 +428,13 @@ void DtlsTransport::incoming(message_ptr message) {
 	mIncomingQueue.push(message);
 	mIncomingQueue.push(message);
 }
 }
 
 
+bool DtlsTransport::outgoing(message_ptr message) {
+	if (message->dscp == 0)
+		message->dscp = mCurrentDscp;
+
+	return Transport::outgoing(std::move(message));
+}
+
 void DtlsTransport::postHandshake() {
 void DtlsTransport::postHandshake() {
 	// Dummy
 	// Dummy
 }
 }

+ 2 - 0
src/dtlstransport.hpp

@@ -53,6 +53,7 @@ public:
 
 
 protected:
 protected:
 	virtual void incoming(message_ptr message) override;
 	virtual void incoming(message_ptr message) override;
+	virtual bool outgoing(message_ptr message) override;
 	virtual void postHandshake();
 	virtual void postHandshake();
 	void runRecvLoop();
 	void runRecvLoop();
 
 
@@ -62,6 +63,7 @@ protected:
 
 
 	Queue<message_ptr> mIncomingQueue;
 	Queue<message_ptr> mIncomingQueue;
 	std::thread mRecvThread;
 	std::thread mRecvThread;
+	std::atomic<unsigned int> mCurrentDscp;
 
 
 #if USE_GNUTLS
 #if USE_GNUTLS
 	gnutls_session_t mSession;
 	gnutls_session_t mSession;

+ 12 - 3
src/icetransport.cpp

@@ -222,8 +222,10 @@ bool IceTransport::send(message_ptr message) {
 }
 }
 
 
 bool IceTransport::outgoing(message_ptr message) {
 bool IceTransport::outgoing(message_ptr message) {
-	return juice_send(mAgent.get(), reinterpret_cast<const char *>(message->data()),
-	                  message->size()) >= 0;
+	// Explicit Congestion Notification takes the least-significant 2 bits of the DS field
+	int ds = int(message->dscp << 2);
+	return juice_send_diffserv(mAgent.get(), reinterpret_cast<const char *>(message->data()),
+	                           message->size(), ds) >= 0;
 }
 }
 
 
 void IceTransport::changeGatheringState(GatheringState state) {
 void IceTransport::changeGatheringState(GatheringState state) {
@@ -330,7 +332,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
       mMid("0"), mGatheringState(GatheringState::New),
       mMid("0"), mGatheringState(GatheringState::New),
       mCandidateCallback(std::move(candidateCallback)),
       mCandidateCallback(std::move(candidateCallback)),
       mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)),
       mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)),
-      mNiceAgent(nullptr, nullptr), mMainLoop(nullptr, nullptr) {
+      mNiceAgent(nullptr, nullptr), mMainLoop(nullptr, nullptr), mOutgoingDscp(0) {
 
 
 	PLOG_DEBUG << "Initializing ICE transport (libnice)";
 	PLOG_DEBUG << "Initializing ICE transport (libnice)";
 
 
@@ -617,6 +619,13 @@ bool IceTransport::send(message_ptr message) {
 }
 }
 
 
 bool IceTransport::outgoing(message_ptr message) {
 bool IceTransport::outgoing(message_ptr message) {
+	std::lock_guard lock(mOutgoingMutex);
+	if (mOutgoingDscp != message->dscp) {
+		mOutgoingDscp = message->dscp;
+		// Explicit Congestion Notification takes the least-significant 2 bits of the DS field
+		int ds = int(message->dscp << 2);
+		nice_agent_set_stream_tos(mNiceAgent.get(), mStreamId, ds); // ToS is the legacy name for DS
+	}
 	return nice_agent_send(mNiceAgent.get(), mStreamId, 1, message->size(),
 	return nice_agent_send(mNiceAgent.get(), mStreamId, 1, message->size(),
 	                       reinterpret_cast<const char *>(message->data())) >= 0;
 	                       reinterpret_cast<const char *>(message->data())) >= 0;
 }
 }

+ 3 - 0
src/icetransport.hpp

@@ -35,6 +35,7 @@
 #include <atomic>
 #include <atomic>
 #include <chrono>
 #include <chrono>
 #include <thread>
 #include <thread>
+#include <mutex>
 
 
 namespace rtc {
 namespace rtc {
 
 
@@ -99,6 +100,8 @@ private:
 	std::unique_ptr<GMainLoop, void (*)(GMainLoop *)> mMainLoop;
 	std::unique_ptr<GMainLoop, void (*)(GMainLoop *)> mMainLoop;
 	std::thread mMainLoopThread;
 	std::thread mMainLoopThread;
 	guint mTimeoutId = 0;
 	guint mTimeoutId = 0;
+	std::mutex mOutgoingMutex;
+	unsigned int mOutgoingDscp;
 
 
 	static string AddressToString(const NiceAddress &addr);
 	static string AddressToString(const NiceAddress &addr);
 
 

+ 3 - 3
src/peerconnection.cpp

@@ -369,7 +369,7 @@ void PeerConnection::onSignalingStateChange(std::function<void(SignalingState st
 std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description) {
 std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description) {
 #if !RTC_ENABLE_MEDIA
 #if !RTC_ENABLE_MEDIA
 	if (mTracks.empty()) {
 	if (mTracks.empty()) {
-		PLOG_WARNING << "Tracks will be inative (not compiled with SRTP support)";
+		PLOG_WARNING << "Tracks will be inative (not compiled with media support)";
 	}
 	}
 #endif
 #endif
 
 
@@ -503,7 +503,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
 			    lower, certificate, verifierCallback,
 			    lower, certificate, verifierCallback,
 			    std::bind(&PeerConnection::forwardMedia, this, _1), stateChangeCallback);
 			    std::bind(&PeerConnection::forwardMedia, this, _1), stateChangeCallback);
 #else
 #else
-			PLOG_WARNING << "Ignoring media support (not compiled with SRTP support)";
+			PLOG_WARNING << "Ignoring media support (not compiled with media support)";
 #endif
 #endif
 		}
 		}
 
 
@@ -872,7 +872,7 @@ void PeerConnection::incomingTrack(Description::Media description) {
 	std::unique_lock lock(mTracksMutex); // we are going to emplace
 	std::unique_lock lock(mTracksMutex); // we are going to emplace
 #if !RTC_ENABLE_MEDIA
 #if !RTC_ENABLE_MEDIA
 	if (mTracks.empty()) {
 	if (mTracks.empty()) {
-		PLOG_WARNING << "Tracks will be inative (not compiled with SRTP support)";
+		PLOG_WARNING << "Tracks will be inative (not compiled with media support)";
 	}
 	}
 #endif
 #endif
 	if (mTracks.find(description.mid()) == mTracks.end()) {
 	if (mTracks.find(description.mid()) == mTracks.end()) {

+ 14 - 3
src/sctptransport.cpp

@@ -88,7 +88,7 @@ void SctpTransport::Cleanup() {
 SctpTransport::SctpTransport(std::shared_ptr<Transport> lower, uint16_t port,
 SctpTransport::SctpTransport(std::shared_ptr<Transport> lower, uint16_t port,
                              message_callback recvCallback, amount_callback bufferedAmountCallback,
                              message_callback recvCallback, amount_callback bufferedAmountCallback,
                              state_callback stateChangeCallback)
                              state_callback stateChangeCallback)
-    : Transport(lower, std::move(stateChangeCallback)), mPort(port),
+    : Transport(lower, std::move(stateChangeCallback)), mPort(port), mPendingRecvCount(0),
       mSendQueue(0, message_size_func), mBufferedAmountCallback(std::move(bufferedAmountCallback)) {
       mSendQueue(0, message_size_func), mBufferedAmountCallback(std::move(bufferedAmountCallback)) {
 	onRecv(recvCallback);
 	onRecv(recvCallback);
 
 
@@ -325,8 +325,16 @@ void SctpTransport::incoming(message_ptr message) {
 	usrsctp_conninput(this, message->data(), message->size(), 0);
 	usrsctp_conninput(this, message->data(), message->size(), 0);
 }
 }
 
 
+bool SctpTransport::outgoing(message_ptr message) {
+	// Set recommended medium-priority DSCP value
+	// See https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18
+	message->dscp = 10; // AF11: Assured Forwarding class 1, low drop probability
+	return Transport::outgoing(std::move(message));
+}
+
 void SctpTransport::doRecv() {
 void SctpTransport::doRecv() {
 	std::lock_guard lock(mRecvMutex);
 	std::lock_guard lock(mRecvMutex);
+	--mPendingRecvCount;
 	try {
 	try {
 		while (true) {
 		while (true) {
 			const size_t bufferSize = 65536;
 			const size_t bufferSize = 65536;
@@ -532,15 +540,17 @@ bool SctpTransport::safeFlush() {
 }
 }
 
 
 void SctpTransport::handleUpcall() {
 void SctpTransport::handleUpcall() {
-	if(!mSock)
+	if (!mSock)
 		return;
 		return;
 
 
 	PLOG_VERBOSE << "Handle upcall";
 	PLOG_VERBOSE << "Handle upcall";
 
 
 	int events = usrsctp_get_events(mSock);
 	int events = usrsctp_get_events(mSock);
 
 
-	if (events & SCTP_EVENT_READ)
+	if (events & SCTP_EVENT_READ && mPendingRecvCount == 0) {
+		++mPendingRecvCount;
 		mProcessor.enqueue(&SctpTransport::doRecv, this);
 		mProcessor.enqueue(&SctpTransport::doRecv, this);
+	}
 
 
 	if (events & SCTP_EVENT_WRITE)
 	if (events & SCTP_EVENT_WRITE)
 		mProcessor.enqueue(&SctpTransport::safeFlush, this);
 		mProcessor.enqueue(&SctpTransport::safeFlush, this);
@@ -551,6 +561,7 @@ int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, uint8_t
 		std::unique_lock lock(mWriteMutex);
 		std::unique_lock lock(mWriteMutex);
 		PLOG_VERBOSE << "Handle write, len=" << len;
 		PLOG_VERBOSE << "Handle write, len=" << len;
 
 
+		auto message = make_message(data, data + len);
 		if (!outgoing(make_message(data, data + len)))
 		if (!outgoing(make_message(data, data + len)))
 			return -1;
 			return -1;
 
 

+ 2 - 0
src/sctptransport.hpp

@@ -77,6 +77,7 @@ private:
 	void shutdown();
 	void shutdown();
 	void close();
 	void close();
 	void incoming(message_ptr message) override;
 	void incoming(message_ptr message) override;
+	bool outgoing(message_ptr message) override;
 
 
 	void doRecv();
 	void doRecv();
 	bool trySendQueue();
 	bool trySendQueue();
@@ -95,6 +96,7 @@ private:
 	struct socket *mSock;
 	struct socket *mSock;
 
 
 	Processor mProcessor;
 	Processor mProcessor;
+	std::atomic<int> mPendingRecvCount;
 	std::mutex mRecvMutex, mSendMutex;
 	std::mutex mRecvMutex, mSendMutex;
 	Queue<message_ptr> mSendQueue;
 	Queue<message_ptr> mSendQueue;
 	std::map<uint16_t, size_t> mBufferedAmount;
 	std::map<uint16_t, size_t> mBufferedAmount;

+ 50 - 56
src/track.cpp

@@ -45,12 +45,30 @@ void Track::close() {
 	setRtcpHandler(nullptr);
 	setRtcpHandler(nullptr);
 }
 }
 
 
-bool Track::send(message_variant data) { return outgoing(make_message(std::move(data))); }
+bool Track::send(message_variant data) {
+	if (mIsClosed)
+		throw std::runtime_error("Track is closed");
+
+	auto direction = mMediaDescription.direction();
+	if ((direction == Description::Direction::RecvOnly ||
+	     direction == Description::Direction::Inactive)) {
+		PLOG_WARNING << "Track media direction does not allow transmission, dropping";
+		return false;
+	}
 
 
-bool Track::send(const byte *data, size_t size) {
-	return outgoing(std::make_shared<Message>(data, data + size, Message::Binary));
+	auto message = make_message(std::move(data));
+
+	if (mRtcpHandler) {
+		message = mRtcpHandler->outgoing(message);
+		if (!message)
+			return false;
+	}
+
+	return outgoing(std::move(message));
 }
 }
 
 
+bool Track::send(const byte *data, size_t size) { return send(binary(data, data + size)); }
+
 std::optional<message_variant> Track::receive() {
 std::optional<message_variant> Track::receive() {
 	if (auto next = mRecvQueue.tryPop())
 	if (auto next = mRecvQueue.tryPop())
 		return to_variant(std::move(**next));
 		return to_variant(std::move(**next));
@@ -88,50 +106,10 @@ void Track::open(shared_ptr<DtlsSrtpTransport> transport) {
 }
 }
 #endif
 #endif
 
 
-bool Track::outgoing(message_ptr message) {
-
-	if (mRtcpHandler) {
-		message = mRtcpHandler->outgoing(message);
-		if (!message)
-			return false;
-	}
-
-	auto direction = mMediaDescription.direction();
-	if ((direction == Description::Direction::RecvOnly ||
-	     direction == Description::Direction::Inactive) &&
-	    message->type != Message::Control) {
-		PLOG_WARNING << "Track media direction does not allow transmission, dropping";
-		return false;
-	}
-
-	if (mIsClosed)
-		throw std::runtime_error("Track is closed");
-
-	if (message->size() > maxMessageSize())
-		throw std::runtime_error("Message size exceeds limit");
-
-#if RTC_ENABLE_MEDIA
-	auto transport = mDtlsSrtpTransport.lock();
-	if (!transport)
-		throw std::runtime_error("Track transport is not open");
-
-	return transport->sendMedia(message);
-#else
-	PLOG_WARNING << "Ignoring track send (not compiled with SRTP support)";
-	return false;
-#endif
-}
-
 void Track::incoming(message_ptr message) {
 void Track::incoming(message_ptr message) {
 	if (!message)
 	if (!message)
 		return;
 		return;
 
 
-	if (mRtcpHandler) {
-		message = mRtcpHandler->incoming(message);
-		if (!message)
-			return;
-	}
-
 	auto direction = mMediaDescription.direction();
 	auto direction = mMediaDescription.direction();
 	if ((direction == Description::Direction::SendOnly ||
 	if ((direction == Description::Direction::SendOnly ||
 	     direction == Description::Direction::Inactive) &&
 	     direction == Description::Direction::Inactive) &&
@@ -140,30 +118,46 @@ void Track::incoming(message_ptr message) {
 		return;
 		return;
 	}
 	}
 
 
+	if (mRtcpHandler) {
+		message = mRtcpHandler->incoming(message);
+		if (!message)
+			return;
+	}
+
 	// Tail drop if queue is full
 	// Tail drop if queue is full
-	if (mRecvQueue.full())
+	if (mRecvQueue.full()) {
+		PLOG_WARNING << "Track incoming queue is full, dropping";
 		return;
 		return;
+	}
 
 
 	mRecvQueue.push(message);
 	mRecvQueue.push(message);
 	triggerAvailable(mRecvQueue.size());
 	triggerAvailable(mRecvQueue.size());
 }
 }
 
 
-void Track::setRtcpHandler(std::shared_ptr<RtcpHandler> handler) {
-	mRtcpHandler = std::move(handler);
-	if (mRtcpHandler) {
-		mRtcpHandler->onOutgoing([&]([[maybe_unused]] const rtc::message_ptr &message) {
+bool Track::outgoing([[maybe_unused]] message_ptr message) {
 #if RTC_ENABLE_MEDIA
 #if RTC_ENABLE_MEDIA
-			auto transport = mDtlsSrtpTransport.lock();
-			if (!transport)
-				throw std::runtime_error("Track transport is not open");
+	auto transport = mDtlsSrtpTransport.lock();
+	if (!transport)
+		throw std::runtime_error("Track transport is not open");
+
+	// Set recommended medium-priority DSCP value
+	// See https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18
+	if (mMediaDescription.type() == "audio")
+		message->dscp = 46; // EF: Expedited Forwarding
+	else
+		message->dscp = 36; // AF42: Assured Forwarding class 4, medium drop probability
 
 
-			return transport->sendMedia(message);
+	return transport->sendMedia(message);
 #else
 #else
-			PLOG_WARNING << "Ignoring track send (not compiled with SRTP support)";
-			return false;
+	PLOG_WARNING << "Ignoring track send (not compiled with media support)";
+	return false;
 #endif
 #endif
-		});
-	}
+}
+
+void Track::setRtcpHandler(std::shared_ptr<RtcpHandler> handler) {
+	mRtcpHandler = std::move(handler);
+	if (mRtcpHandler)
+		mRtcpHandler->onOutgoing(std::bind(&Track::outgoing, this, std::placeholders::_1));
 }
 }
 
 
 bool Track::requestKeyframe() {
 bool Track::requestKeyframe() {

+ 1 - 3
src/transport.hpp

@@ -28,8 +28,6 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-using namespace std::placeholders;
-
 class Transport {
 class Transport {
 public:
 public:
 	enum class State { Disconnected, Connecting, Connected, Completed, Failed };
 	enum class State { Disconnected, Connecting, Connected, Completed, Failed };
@@ -57,7 +55,7 @@ public:
 	void registerIncoming() {
 	void registerIncoming() {
 		if (mLower) {
 		if (mLower) {
 			PLOG_VERBOSE << "Registering incoming callback";
 			PLOG_VERBOSE << "Registering incoming callback";
-			mLower->onRecv(std::bind(&Transport::incoming, this, _1));
+			mLower->onRecv(std::bind(&Transport::incoming, this, std::placeholders::_1));
 		}
 		}
 	}
 	}
 
 

+ 1 - 0
src/websocket.cpp

@@ -36,6 +36,7 @@
 namespace rtc {
 namespace rtc {
 
 
 using std::shared_ptr;
 using std::shared_ptr;
+using namespace std::placeholders;
 
 
 WebSocket::WebSocket(std::optional<Configuration> config)
 WebSocket::WebSocket(std::optional<Configuration> config)
     : mConfig(config ? std::move(*config) : Configuration()),
     : mConfig(config ? std::move(*config) : Configuration()),

+ 1 - 0
test/capi_connectivity.cpp

@@ -161,6 +161,7 @@ static Peer *createPeer(const rtcConfiguration *config) {
 	rtcSetLocalCandidateCallback(peer->pc, candidateCallback);
 	rtcSetLocalCandidateCallback(peer->pc, candidateCallback);
 	rtcSetStateChangeCallback(peer->pc, stateChangeCallback);
 	rtcSetStateChangeCallback(peer->pc, stateChangeCallback);
 	rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback);
 	rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback);
+	rtcSetSignalingStateChangeCallback(peer->pc, signalingStateCallback);
 
 
 	return peer;
 	return peer;
 }
 }