Projects
Multimedia
libdatachannel
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 8
View file
libdatachannel.spec
Changed
@@ -16,7 +16,7 @@ # -%define libname %{name}0_23 +%define libname %{name}0_24 Name: libdatachannel Version: 0 Release: 0
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="obs_scm"> <param name="filename">libdatachannel</param> - <param name="revision">d9391849bdb183854af7d4d92cae8f6a918d7a40</param> + <param name="revision">c6696d157b5612df2a741d9a03b192b47ab6cefb</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/paullouisageneau/libdatachannel.git</param>
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/build-gnutls.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/build-gnutls.yml
Changed
@@ -8,7 +8,7 @@ build-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: sudo apt update && sudo apt install libgnutls28-dev nettle-dev libsrtp2-dev - name: submodules @@ -22,7 +22,7 @@ build-macos: runs-on: macos-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: brew install gnutls nettle - name: submodules
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/build-mbedtls.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/build-mbedtls.yml
Changed
@@ -8,15 +8,15 @@ build-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Homebrew uses: Homebrew/actions/setup-homebrew@master - name: Install Mbed TLS - run: brew update && brew install mbedtls + run: brew update && brew install mbedtls@3 - name: submodules run: git submodule update --init --recursive --depth 1 - name: cmake - run: cmake -B build -DUSE_MBEDTLS=1 -DWARNINGS_AS_ERRORS=1 -DCMAKE_PREFIX_PATH=$(brew --prefix mbedtls) + run: cmake -B build -DUSE_MBEDTLS=1 -DWARNINGS_AS_ERRORS=1 -DCMAKE_PREFIX_PATH=$(brew --prefix mbedtls@3) - name: make run: (cd build; make -j2) - name: test @@ -24,13 +24,13 @@ build-macos: runs-on: macos-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Mbed TLS - run: brew update && brew install mbedtls + run: brew update && brew install mbedtls@3 - name: submodules run: git submodule update --init --recursive --depth 1 - name: cmake - run: cmake -B build -DUSE_MBEDTLS=1 -DWARNINGS_AS_ERRORS=1 -DENABLE_LOCAL_ADDRESS_TRANSLATION=1 -DCMAKE_PREFIX_PATH=$(brew --prefix mbedtls) + run: cmake -B build -DUSE_MBEDTLS=1 -DWARNINGS_AS_ERRORS=1 -DENABLE_LOCAL_ADDRESS_TRANSLATION=1 -DCMAKE_PREFIX_PATH=$(brew --prefix mbedtls@3) - name: make run: (cd build; make -j2) - name: test
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/build-nice.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/build-nice.yml
Changed
@@ -8,7 +8,7 @@ build-nice: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: sudo apt update && sudo apt install libgnutls28-dev libnice-dev - name: submodules
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/build-nomedia.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/build-nomedia.yml
Changed
@@ -8,7 +8,7 @@ build-nomedia: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: sudo apt update && sudo apt install libssl-dev - name: submodules @@ -22,7 +22,7 @@ build-nomedia-windows: runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: ilammy/msvc-dev-cmd@v1 - name: install packages run: choco install openssl
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/build-nowebsocket.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/build-nowebsocket.yml
Changed
@@ -10,7 +10,7 @@ build-nowebsocket: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: sudo apt update && sudo apt install libssl-dev libsrtp2-dev - name: submodules
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/build-openssl.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/build-openssl.yml
Changed
@@ -8,7 +8,7 @@ build-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: sudo apt update && sudo apt install libssl-dev libsrtp2-dev - name: submodules @@ -22,7 +22,7 @@ build-macos: runs-on: macos-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: HOMEBREW_NO_INSTALL_CLEANUP=1 brew reinstall openssl@3 - name: submodules @@ -38,7 +38,7 @@ build-windows: runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: ilammy/msvc-dev-cmd@v1 - name: install packages run: choco install openssl
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/.github/workflows/check-version.yml -> _service:obs_scm:libdatachannel-0.24.3.obscpio/.github/workflows/check-version.yml
Changed
@@ -8,7 +8,7 @@ check-version: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: install packages run: sudo apt update && sudo apt install libssl-dev libsrtp2-dev - name: submodules
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/CMakeLists.txt -> _service:obs_scm:libdatachannel-0.24.3.obscpio/CMakeLists.txt
Changed
@@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.13) project(libdatachannel - VERSION 0.23.3 + VERSION 0.24.3 LANGUAGES CXX) set(PROJECT_DESCRIPTION "C/C++ WebRTC network library featuring Data Channels, Media Transport, and WebSockets") @@ -466,7 +466,7 @@ target_compile_definitions(datachannel PRIVATE USE_NICE=0) target_compile_definitions(datachannel-static PRIVATE USE_NICE=0) if(USE_SYSTEM_JUICE) - find_package(LibJuice REQUIRED) + find_package(LibJuice 1.7.0 REQUIRED) target_compile_definitions(datachannel PRIVATE RTC_SYSTEM_JUICE=1) target_compile_definitions(datachannel-static PRIVATE RTC_SYSTEM_JUICE=1) target_link_libraries(datachannel PRIVATE LibJuice::LibJuice)
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/DOC.md -> _service:obs_scm:libdatachannel-0.24.3.obscpio/DOC.md
Changed
@@ -103,7 +103,7 @@ - `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) - `iceTransportPolicy` (optional): ICE transport policy, if set to `RTC_TRANSPORT_POLICY_RELAY`, the PeerConnection will emit only relayed candidates (0 or `RTC_TRANSPORT_POLICY_ALL` if default) - - `enableIceTcp`: if true, generate TCP candidates for ICE (ignored with libjuice as ICE backend) + - `enableIceTcp`: if true, generate TCP candidates for ICE - `enableIceUdpMux`: if true, connections are multiplexed on the same UDP port (should be combined with `portRangeBegin` and `portRangeEnd`, ignored with libnice as ICE backend) - `disableAutoNegotiation`: if true, the user is responsible for calling `rtcSetLocalDescription` after creating a Data Channel and after setting the remote description - `forceMediaTransport`: if true, the connection allocates the SRTP media transport even if no tracks are present (necessary to add tracks during later renegotiation)
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/README.md -> _service:obs_scm:libdatachannel-0.24.3.obscpio/README.md
Changed
@@ -123,7 +123,7 @@ ws.onMessage((std::variant<rtc::binary, rtc::string> message) { if (std::holds_alternative<rtc::string>(message)) { - std::cout << "WebSocket received: " << std::get<rtc::string>(message) << endl; + std::cout << "WebSocket received: " << std::get<rtc::string>(message) << std::endl; } });
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/configuration.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/configuration.hpp
Changed
@@ -72,7 +72,7 @@ // Options CertificateType certificateType = CertificateType::Default; TransportPolicy iceTransportPolicy = TransportPolicy::All; - bool enableIceTcp = false; // libnice only + bool enableIceTcp = false; bool enableIceUdpMux = false; // libjuice only bool disableAutoNegotiation = false; bool disableAutoGathering = false;
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/description.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/description.hpp
Changed
@@ -293,6 +293,8 @@ static Type stringToType(const string &typeString); static string typeToString(Type type); + string sessionId() const; + private: optional<Candidate> defaultCandidate() const; shared_ptr<Entry> createEntry(string mline, string mid, Direction dir);
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/global.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/global.hpp
Changed
@@ -31,8 +31,7 @@ RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr); -RTC_CPP_EXPORT void Preload(); -RTC_CPP_EXPORT std::shared_future<void> Cleanup(); +RTC_CPP_EXPORT void SetThreadPoolSize(unsigned int count); // 0: hardware concurrency struct SctpSettings { // For the following settings, not set means optimized default @@ -52,6 +51,10 @@ RTC_CPP_EXPORT void SetSctpSettings(SctpSettings s); +// Optional global preload and cleanup +RTC_CPP_EXPORT void Preload(); +RTC_CPP_EXPORT std::shared_future<void> Cleanup(); + RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, LogLevel level); } // namespace rtc
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/pacinghandler.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/pacinghandler.hpp
Changed
@@ -40,6 +40,7 @@ std::queue<message_ptr> mRtpBuffer; void schedule(const message_callback &send); + void run(const message_callback &send); }; } // namespace rtc
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/rtc.h -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/rtc.h
Changed
@@ -191,7 +191,7 @@ const char *bindAddress; // libjuice only, NULL means any rtcCertificateType certificateType; rtcTransportPolicy iceTransportPolicy; - bool enableIceTcp; // libnice only + bool enableIceTcp; bool enableIceUdpMux; // libjuice only bool disableAutoNegotiation; bool forceMediaTransport; @@ -352,6 +352,14 @@ uint8_t playoutDelayId; uint16_t playoutDelayMin; uint16_t playoutDelayMax; + + uint8_t colorSpaceId; + uint8_t colorChromaSitingHorz; + uint8_t colorChromaSitingVert; + uint8_t colorRange; + uint8_t colorPrimaries; + uint8_t colorTransfer; + uint8_t colorMatrix; } rtcPacketizerInit; // Deprecated, do not use @@ -505,12 +513,10 @@ #endif -// Optional global preload and cleanup - -RTC_C_EXPORT void rtcPreload(void); -RTC_C_EXPORT void rtcCleanup(void); +// Global settings -// SCTP global settings +// Note: Applied when threads are spawned +RTC_C_EXPORT int rtcSetThreadPoolSize(unsigned int count); typedef struct { int recvBufferSize; // in bytes, <= 0 means optimized default @@ -530,6 +536,10 @@ // Note: SCTP settings apply to newly-created PeerConnections only RTC_C_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings); +// Optional global preload and cleanup +RTC_C_EXPORT void rtcPreload(void); +RTC_C_EXPORT void rtcCleanup(void); + #ifdef __cplusplus } // extern "C" #endif
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/rtcpreceivingsession.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/rtcpreceivingsession.hpp
Changed
@@ -18,6 +18,7 @@ #include "rtp.hpp" #include <atomic> +#include <mutex> #define RTP_SEQ_MOD (1<<16) @@ -37,6 +38,13 @@ deprecated("Use Track::requestKeyframe()") inline bool requestKeyframe() { return false; }; deprecated("Use Track::requestBitrate()") inline void requestBitrate(unsigned int) {}; + struct SyncTimestamps { + uint64_t rtpTimestamp; + uint64_t ntpTimestamp; + }; + + SyncTimestamps getSyncTimestamps(); + protected: void pushREMB(const message_callback &send, unsigned int bitrate); void pushRR(const message_callback &send,unsigned int lastSrDelay); @@ -58,9 +66,10 @@ uint32_t mTransit = 0; // relative trans time for prev pkt uint32_t mJitter = 0; - uint64_t mSyncRTPTS, mSyncNTPTS; + SyncTimestamps mSyncTimestamps{0,0}; std::atomic<unsigned int> mRequestedBitrate = 0; + std::mutex mSyncMutex; }; } // namespace rtc
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/rtp.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/rtp.hpp
Changed
@@ -169,8 +169,8 @@ nodiscard uint32_t octetCount() const; nodiscard uint32_t senderSSRC() const; - nodiscard const RtcpReportBlock *getReportBlock(int num) const; - nodiscard RtcpReportBlock *getReportBlock(int num); + nodiscard const RtcpReportBlock *getReportBlock(int num) const; // nullptr if out-of-bounds + nodiscard RtcpReportBlock *getReportBlock(int num); // nullptr if out-of-bounds nodiscard unsigned int size(unsigned int reportCount); nodiscard size_t getSize() const; @@ -254,8 +254,8 @@ bool isSenderReport(); bool isReceiverReport(); - nodiscard RtcpReportBlock *getReportBlock(int num); - nodiscard const RtcpReportBlock *getReportBlock(int num) const; + nodiscard RtcpReportBlock *getReportBlock(int num); // nullptr if out-of-bounds + nodiscard const RtcpReportBlock *getReportBlock(int num) const; // nullptr if out-of-bounds nodiscard size_t getSize() const; void preparePacket(SSRC senderSSRC, uint8_t reportCount); @@ -269,7 +269,7 @@ char _id4; // Unique identifier ('R' 'E' 'M' 'B') uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask) - SSRC _ssrc1; + SSRC _ssrcs1; nodiscard static size_t SizeWithSSRCs(int count); @@ -277,8 +277,16 @@ void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate); void setBitrate(unsigned int numSSRC, unsigned int in_bitrate); - void setSsrc(int iterator, SSRC newSssrc); - unsigned int getNumSSRC(); + SSRC getSSRC(int num) const; + void setSSRC(int num, SSRC newSsrc); + bool hasValidId() const; + int getSSRCCount() const; + unsigned int getBitrate() const; + + // Deprecated + deprecated("use setSSRC") void setSsrc(int num, SSRC newSssrc); + deprecated("use getSSRCCount") unsigned int getNumSSRC() const; + deprecated("use getSSRCCount") unsigned int getNumSSRC(); unsigned int getBitrate(); };
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/rtppacketizationconfig.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/rtppacketizationconfig.hpp
Changed
@@ -74,6 +74,15 @@ uint16_t playoutDelayMin = 0; uint16_t playoutDelayMax = 0; + // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/color-space/ + uint8_t colorSpaceId = 0; // the negotiated ID of color space header extension + uint8_t colorChromaSitingHorz = 0; // unspecified + uint8_t colorChromaSitingVert = 0; // unspecified + uint8_t colorRange = 2; // full range + uint8_t colorPrimaries = 1; // BT.709-6 + uint8_t colorTransfer = 1; // BT.709-6 + uint8_t colorMatrix = 1; // BT.709-6 + /// Construct RTP configuration used in packetization process /// @param ssrc SSRC of source /// @param cname CNAME of source
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/include/rtc/version.h -> _service:obs_scm:libdatachannel-0.24.3.obscpio/include/rtc/version.h
Changed
@@ -2,8 +2,8 @@ #define RTC_VERSION_H #define RTC_VERSION_MAJOR 0 -#define RTC_VERSION_MINOR 23 +#define RTC_VERSION_MINOR 24 #define RTC_VERSION_PATCH 3 -#define RTC_VERSION "0.23.3" +#define RTC_VERSION "0.24.3" #endif
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/pages/content/pages/reference.md -> _service:obs_scm:libdatachannel-0.24.3.obscpio/pages/content/pages/reference.md
Changed
@@ -106,7 +106,7 @@ - `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) - `iceTransportPolicy` (optional): ICE transport policy, if set to `RTC_TRANSPORT_POLICY_RELAY`, the PeerConnection will emit only relayed candidates (0 or `RTC_TRANSPORT_POLICY_ALL` if default) - - `enableIceTcp`: if true, generate TCP candidates for ICE (ignored with libjuice as ICE backend) + - `enableIceTcp`: if true, generate TCP candidates for ICE - `enableIceUdpMux`: if true, connections are multiplexed on the same UDP port (should be combined with `portRangeBegin` and `portRangeEnd`, ignored with libnice as ICE backend) - `disableAutoNegotiation`: if true, the user is responsible for calling `rtcSetLocalDescription` after creating a Data Channel and after setting the remote description - `forceMediaTransport`: if true, the connection allocates the SRTP media transport even if no tracks are present (necessary to add tracks during later renegotiation) @@ -872,6 +872,7 @@ typedef struct { bool disableTlsVerification; + const char *proxyServer; const char **protocols; int protocolsCount; int connectionTimeoutMs; @@ -887,6 +888,7 @@ - `url`: a null-terminated string representing the fully-qualified URL to open. - `config`: a structure with the following parameters: - `disableTlsVerification`: if true, don't verify the TLS certificate, else try to verify it if possible + - `proxyServer` (optional): address of proxy server as string, only non-authenticated HTTP for now (NULL if unused) - `protocols` (optional): an array of pointers on null-terminated protocol names (NULL if unused) - `protocolsCount` (optional): number of URLs in the array pointed by `protocols` (0 if unused) - `connectionTimeoutMs` (optional): connection timeout in milliseconds (0 if default, < 0 if disabled)
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/av1rtppacketizer.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/av1rtppacketizer.cpp
Changed
@@ -48,12 +48,16 @@ std::vector<binary> AV1RtpPacketizer::extractTemporalUnitObus(const binary &data) { std::vector<binary> obus; - if (data.size() <= 2 || (data.at(0) != obuTemporalUnitDelimiter.at(0)) || - (data.at(1) != obuTemporalUnitDelimiter.at(1))) { + if (data.size() == 0) { return {}; } - size_t index = 2; + // VAAPI doesn't seem to include delimiters + size_t index = 0; + if (data.size() > 2 && (data.at(0) == obuTemporalUnitDelimiter.at(0)) && + (data.at(1) == obuTemporalUnitDelimiter.at(1))) { + index = 2; + } while (index < data.size()) { if ((data.at(index) & obuHasSizeMask) == byte(0)) { return obus;
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/capi.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/capi.cpp
Changed
@@ -278,6 +278,13 @@ config->playoutDelayId = init->playoutDelayId; config->playoutDelayMin = init->playoutDelayMin; config->playoutDelayMax = init->playoutDelayMax; + config->colorSpaceId = init->colorSpaceId; + config->colorChromaSitingHorz = init->colorChromaSitingHorz; + config->colorChromaSitingVert = init->colorChromaSitingVert; + config->colorRange = init->colorRange; + config->colorPrimaries = init->colorPrimaries; + config->colorTransfer = init->colorTransfer; + config->colorMatrix = init->colorMatrix; return config; } @@ -1089,7 +1096,7 @@ case RTC_CODEC_OPUS: case RTC_CODEC_PCMU: case RTC_CODEC_PCMA: - case RTC_CODEC_AAC: + case RTC_CODEC_AAC: case RTC_CODEC_G722: { auto audio = std::make_unique<Description::Audio>(mid, direction); switch (init->codec) { @@ -1680,28 +1687,11 @@ #endif -void rtcPreload() { - try { - rtc::Preload(); - } catch (const std::exception &e) { - PLOG_ERROR << e.what(); - } -} - -void rtcCleanup() { - try { - size_t count = eraseAll(); - if (count != 0) { - PLOG_INFO << count << " objects were not properly destroyed before cleanup"; - } - - if (rtc::Cleanup().wait_for(10s) == std::future_status::timeout) - throw std::runtime_error( - "Cleanup timeout (possible deadlock or undestructible object)"); - - } catch (const std::exception &e) { - PLOG_ERROR << e.what(); - } +int rtcSetThreadPoolSize(unsigned int count) { + return wrap(& { + SetThreadPoolSize(count); + return RTC_ERR_SUCCESS; + }); } int rtcSetSctpSettings(const rtcSctpSettings *settings) { @@ -1752,3 +1742,28 @@ return RTC_ERR_SUCCESS; }); } + +void rtcPreload() { + try { + rtc::Preload(); + } catch (const std::exception &e) { + PLOG_ERROR << e.what(); + } +} + +void rtcCleanup() { + try { + size_t count = eraseAll(); + if (count != 0) { + PLOG_INFO << count << " objects were not properly destroyed before cleanup"; + } + + if (rtc::Cleanup().wait_for(10s) == std::future_status::timeout) + throw std::runtime_error( + "Cleanup timeout (possible deadlock or undestructible object)"); + + } catch (const std::exception &e) { + PLOG_ERROR << e.what(); + } +} +
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/description.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/description.cpp
Changed
@@ -162,6 +162,8 @@ addCandidate(Candidate(attr, bundleMid())); } else if (key == "end-of-candidates") { mEnded = true; + } else if (key == "group") { + // Ignore, it will be generated automatically } else if (current) { current->parseSdpLine(std::move(line)); } else { @@ -542,6 +544,8 @@ int Description::mediaCount() const { return int(mEntries.size()); } +string Description::sessionId() const { return mSessionId; } + Description::Entry::Entry(const string &mline, string mid, Direction dir) : mMid(std::move(mid)), mDirection(dir) {
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/global.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/global.cpp
Changed
@@ -83,11 +83,12 @@ plogInit(severity, appender); } +void SetThreadPoolSize(unsigned int count) { impl::Init::Instance().setThreadPoolSize(count); } +void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); } + void Preload() { impl::Init::Instance().preload(); } std::shared_future<void> Cleanup() { return impl::Init::Instance().cleanup(); } -void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); } - std::ostream &operator<<(std::ostream &out, LogLevel level) { switch (level) { case LogLevel::Fatal:
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/certificate.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/certificate.cpp
Changed
@@ -510,9 +510,6 @@ auto *commonNameBytes = reinterpret_cast<unsigned char *>(const_cast<char *>(commonName.c_str())); - if (!X509_set_pubkey(x509.get(), pkey.get())) - throw std::runtime_error("Unable to set certificate public key"); - if (!X509_gmtime_adj(X509_getm_notBefore(x509.get()), 3600 * -1) || !X509_gmtime_adj(X509_getm_notAfter(x509.get()), 3600 * 24 * 365) || #if OPENSSL_VERSION_NUMBER >= 0x30000000 @@ -528,6 +525,9 @@ !X509_set_issuer_name(x509.get(), name.get())) throw std::runtime_error("Unable to set certificate properties"); + if (!X509_set_pubkey(x509.get(), pkey.get())) + throw std::runtime_error("Unable to set certificate public key"); + if (!X509_sign(x509.get(), pkey.get(), EVP_sha256())) throw std::runtime_error("Unable to auto-sign certificate");
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/dtlstransport.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/dtlstransport.cpp
Changed
@@ -896,8 +896,11 @@ } PLOG_VERBOSE << "Incoming size=" << message->size(); - mIncomingQueue.push(message); - enqueueRecv(); + if(mIncomingQueue.tryPush(message)) { + enqueueRecv(); + } else { + PLOG_VERBOSE << "DTLS incoming queue is full, dropping"; + } } bool DtlsTransport::outgoing(message_ptr message) {
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/icetransport.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/icetransport.cpp
Changed
@@ -90,10 +90,6 @@ jconfig.cb_recv = IceTransport::RecvCallback; jconfig.user_ptr = this; - if (config.enableIceTcp) { - PLOG_WARNING << "ICE-TCP is not supported with libjuice"; - } - if (config.enableIceUdpMux) { PLOG_DEBUG << "Enabling ICE UDP mux"; jconfig.concurrency_mode = JUICE_CONCURRENCY_MODE_MUX; @@ -134,6 +130,10 @@ if (!mAgent) throw std::runtime_error("Failed to create the ICE agent"); + // ICE-TCP + juice_set_ice_tcp_mode(mAgent.get(), config.enableIceTcp ? JUICE_ICE_TCP_MODE_ACTIVE + : JUICE_ICE_TCP_MODE_NONE); + // Add TURN servers for (const auto &server : servers) if (!server.hostname.empty() && server.type != IceServer::Type::Stun) @@ -451,7 +451,8 @@ // has been deprecated in this specification. // libnice defaults to aggressive nomation therefore we change to regular nomination. // See https://gitlab.freedesktop.org/libnice/libnice/-/merge_requests/125 - NiceAgentOption flags = NICE_AGENT_OPTION_REGULAR_NOMINATION; + // Enable RFC 7675 ICE consent freshness support (requires libnice 0.1.19) + NiceAgentOption flags = static_cast<NiceAgentOption>(NICE_AGENT_OPTION_REGULAR_NOMINATION | NICE_AGENT_OPTION_CONSENT_FRESHNESS); // Create agent mNiceAgent = decltype(mNiceAgent)( @@ -481,10 +482,7 @@ // the characteristics of the associated data. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-pacing-timer", 25, nullptr); - // Enable RFC 7675 ICE consent freshness support (requires libnice 0.1.19) g_object_set(G_OBJECT(mNiceAgent.get()), "keepalive-conncheck", TRUE, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "consent-freshness", TRUE, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "upnp", FALSE, nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "upnp-timeout", 200, nullptr); @@ -657,8 +655,17 @@ IceTransport::~IceTransport() { PLOG_DEBUG << "Destroying ICE transport"; + + g_signal_handlers_disconnect_by_func(G_OBJECT(mNiceAgent.get()), + (gpointer)StateChangeCallback, this); + g_signal_handlers_disconnect_by_func(G_OBJECT(mNiceAgent.get()), + (gpointer)CandidateCallback, this); + g_signal_handlers_disconnect_by_func(G_OBJECT(mNiceAgent.get()), + (gpointer)GatheringDoneCallback, this); + nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(MainLoop->get()), NULL, NULL); + nice_agent_remove_stream(mNiceAgent.get(), mStreamId); mNiceAgent.reset();
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/init.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/init.cpp
Changed
@@ -96,6 +96,12 @@ return mCleanupFuture; } +void Init::setThreadPoolSize(unsigned int count) { + std::lock_guard lock(mMutex); + mThreadPoolSize = count; + +} + void Init::setSctpSettings(SctpSettings s) { std::lock_guard lock(mMutex); if (mGlobal) @@ -118,8 +124,8 @@ throw std::runtime_error("WSAStartup failed, error=" + std::to_string(WSAGetLastError())); #endif - int concurrency = std::thread::hardware_concurrency(); - int count = std::max(concurrency, MIN_THREADPOOL_SIZE); + unsigned int count = mThreadPoolSize > 0 ? mThreadPoolSize : std::thread::hardware_concurrency(); + count = std::max(count, MIN_THREADPOOL_SIZE); PLOG_DEBUG << "Spawning " << count << " threads"; ThreadPool::Instance().spawn(count);
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/init.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/init.hpp
Changed
@@ -32,6 +32,8 @@ init_token token(); void preload(); std::shared_future<void> cleanup(); + + void setThreadPoolSize(unsigned int count); void setSctpSettings(SctpSettings s); private: @@ -45,6 +47,7 @@ weak_ptr<void> mWeak; bool mInitialized = false; SctpSettings mCurrentSctpSettings = {}; + unsigned int mThreadPoolSize = 0; std::mutex mMutex; std::shared_future<void> mCleanupFuture;
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/internals.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/internals.hpp
Changed
@@ -45,7 +45,7 @@ const size_t RECV_QUEUE_LIMIT = 1024; // Max per-channel queue size (messages) -const int MIN_THREADPOOL_SIZE = 4; // Minimum number of threads in the global thread pool (>= 2) +const unsigned int MIN_THREADPOOL_SIZE = 2; // Minimum number of threads in the global thread pool (>= 2) const size_t DEFAULT_MTU = RTC_DEFAULT_MTU; // defined in rtc.h
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/peerconnection.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/peerconnection.cpp
Changed
@@ -162,52 +162,52 @@ auto transport = std::make_shared<IceTransport>( config, weak_bind(&PeerConnection::processLocalCandidate, this, _1), this, weak_this = weak_from_this()(IceTransport::State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (transportState) { - case IceTransport::State::Connecting: - changeIceState(IceState::Checking); - changeState(State::Connecting); - break; - case IceTransport::State::Connected: - changeIceState(IceState::Connected); - initDtlsTransport(); - break; - case IceTransport::State::Completed: - changeIceState(IceState::Completed); - break; - case IceTransport::State::Failed: - changeIceState(IceState::Failed); - changeState(State::Failed); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - case IceTransport::State::Disconnected: - changeIceState(IceState::Disconnected); - changeState(State::Disconnected); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - default: - // Ignore - break; - } + if (auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case IceTransport::State::Connecting: + changeIceState(IceState::Checking); + changeState(State::Connecting); + break; + case IceTransport::State::Connected: + changeIceState(IceState::Connected); + initDtlsTransport(); + break; + case IceTransport::State::Completed: + changeIceState(IceState::Completed); + break; + case IceTransport::State::Failed: + changeIceState(IceState::Failed); + changeState(State::Failed); + mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); + break; + case IceTransport::State::Disconnected: + changeIceState(IceState::Disconnected); + changeState(State::Disconnected); + mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); + break; + default: + // Ignore + break; + } + }); }, this, weak_this = weak_from_this()(IceTransport::GatheringState gatheringState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (gatheringState) { - case IceTransport::GatheringState::InProgress: - changeGatheringState(GatheringState::InProgress); - break; - case IceTransport::GatheringState::Complete: - endLocalCandidates(); - changeGatheringState(GatheringState::Complete); - break; - default: - // Ignore - break; - } + if (auto locked = weak_this.lock()) + std::invoke(=() { + switch (gatheringState) { + case IceTransport::GatheringState::InProgress: + changeGatheringState(GatheringState::InProgress); + break; + case IceTransport::GatheringState::Complete: + endLocalCandidates(); + changeGatheringState(GatheringState::Complete); + break; + default: + // Ignore + break; + } + }); }); return emplaceTransport(this, &mIceTransport, std::move(transport)); @@ -241,34 +241,33 @@ auto certificate = mCertificate.get(); auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1); - auto dtlsStateChangeCallback = - this, weak_this = weak_from_this()(DtlsTransport::State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - - switch (transportState) { - case DtlsTransport::State::Connected: - if (auto remote = remoteDescription(); remote && remote->hasApplication()) - initSctpTransport(); - else - changeState(State::Connected); - - mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); - break; - case DtlsTransport::State::Failed: - changeState(State::Failed); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - case DtlsTransport::State::Disconnected: - changeState(State::Disconnected); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - default: - // Ignore - break; - } - }; + auto dtlsStateChangeCallback = this, weak_this = weak_from_this()( + DtlsTransport::State transportState) { + if (auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case DtlsTransport::State::Connected: + if (auto remote = remoteDescription(); remote && remote->hasApplication()) + initSctpTransport(); + else + changeState(State::Connected); + + mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this()); + break; + case DtlsTransport::State::Failed: + changeState(State::Failed); + mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); + break; + case DtlsTransport::State::Disconnected: + changeState(State::Disconnected); + mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); + break; + default: + // Ignore + break; + } + }); + }; shared_ptr<DtlsTransport> transport; auto local = localDescription(); @@ -329,28 +328,28 @@ lower, config, std::move(ports), weak_bind(&PeerConnection::forwardMessage, this, _1), weak_bind(&PeerConnection::forwardBufferedAmount, this, _1, _2), this, weak_this = weak_from_this()(SctpTransport::State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - - switch (transportState) { - case SctpTransport::State::Connected: - changeState(State::Connected); - assignDataChannels(); - mProcessor.enqueue(&PeerConnection::openDataChannels, shared_from_this()); - break; - case SctpTransport::State::Failed: - changeState(State::Failed); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - case SctpTransport::State::Disconnected: - changeState(State::Disconnected); - mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); - break; - default: - // Ignore - break; - } + if (auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case SctpTransport::State::Connected: + changeState(State::Connected); + assignDataChannels(); + mProcessor.enqueue(&PeerConnection::openDataChannels, + shared_from_this()); + break; + case SctpTransport::State::Failed: + changeState(State::Failed); + mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); + break; + case SctpTransport::State::Disconnected: + changeState(State::Disconnected); + mProcessor.enqueue(&PeerConnection::remoteClose, shared_from_this()); + break; + default: + // Ignore + break; + } + }); }); return emplaceTransport(this, &mSctpTransport, std::move(transport)); @@ -571,39 +570,66 @@ if (message->type == Message::Control) { std::set<uint32_t> ssrcs; size_t offset = 0; - while ((sizeof(RtcpHeader) + offset) <= message->size()) { + while (offset + sizeof(RtcpHeader) <= message->size()) { auto header = reinterpret_cast<RtcpHeader *>(message->data() + offset); - if (header->lengthInBytes() > message->size() - offset) { + size_t length = header->lengthInBytes(); + if (offset + length > message->size()) { COUNTER_MEDIA_TRUNCATED++; break; } - offset += header->lengthInBytes(); - if (header->payloadType() == 205 || header->payloadType() == 206) { - auto rtcpfb = reinterpret_cast<RtcpFbHeader *>(header); - ssrcs.insert(rtcpfb->packetSenderSSRC()); - ssrcs.insert(rtcpfb->mediaSourceSSRC()); - - } else if (header->payloadType() == 200) { - auto rtcpsr = reinterpret_cast<RtcpSr *>(header); - ssrcs.insert(rtcpsr->senderSSRC()); - for (int i = 0; i < rtcpsr->header.reportCount(); ++i) - ssrcs.insert(rtcpsr->getReportBlock(i)->getSSRC()); - } else if (header->payloadType() == 201) { - auto rtcprr = reinterpret_cast<RtcpRr *>(header); - ssrcs.insert(rtcprr->senderSSRC()); - for (int i = 0; i < rtcprr->header.reportCount(); ++i) - ssrcs.insert(rtcprr->getReportBlock(i)->getSSRC()); - } else if (header->payloadType() == 202) { - auto sdes = reinterpret_cast<RtcpSdes *>(header); - if (!sdes->isValid()) { - PLOG_WARNING << "RTCP SDES packet is invalid"; - continue; + switch(header->payloadType()) { + case 200: // SR + if (length >= sizeof(RtcpSr)) { + auto rtcpsr = reinterpret_cast<RtcpSr *>(header); + ssrcs.insert(rtcpsr->senderSSRC()); + for (int i = 0; i < rtcpsr->header.reportCount(); ++i) + if (const auto *reportBlock = rtcpsr->getReportBlock(i)) + ssrcs.insert(reportBlock->getSSRC()); } - for (unsigned int i = 0; i < sdes->chunksCount(); i++) { - auto chunk = sdes->getChunk(i); - ssrcs.insert(chunk->ssrc()); + break; + + case 201: // RR + if (length >= sizeof(RtcpRr)) { + auto rtcprr = reinterpret_cast<RtcpRr *>(header); + ssrcs.insert(rtcprr->senderSSRC()); + for (int i = 0; i < rtcprr->header.reportCount(); ++i) + if (const auto *reportBlock = rtcprr->getReportBlock(i)) + ssrcs.insert(reportBlock->getSSRC()); } - } else { + break; + + case 202: // SDES + if (length >= sizeof(RtcpSdes)) { + auto sdes = reinterpret_cast<RtcpSdes *>(header); + if (!sdes->isValid()) { + PLOG_WARNING << "RTCP SDES packet is invalid"; + continue; + } + for (unsigned int i = 0; i < sdes->chunksCount(); i++) { + auto chunk = sdes->getChunk(i); + ssrcs.insert(chunk->ssrc()); + } + } + break; + + + case 205: // FB + case 206: + if (length >= sizeof(RtcpFbHeader)) { + auto rtcpfb = reinterpret_cast<RtcpFbHeader *>(header); + ssrcs.insert(rtcpfb->packetSenderSSRC()); + ssrcs.insert(rtcpfb->mediaSourceSSRC()); + if (header->payloadType() == 206 && header->reportCount() == 15 && + length >= sizeof(RtcpRemb)) { + auto remb = reinterpret_cast<RtcpRemb *>(header); + if (remb->hasValidId()) + for (int i = 0; i < remb->getSSRCCount(); ++i) + ssrcs.insert(remb->getSSRC(i)); + } + } + break; + + default: // PT=203 == Goodbye // PT=204 == Application Specific // PT=207 == Extended Report @@ -611,7 +637,9 @@ header->payloadType() != 207) { COUNTER_UNKNOWN_PACKET_TYPE++; } + break; } + offset += header->lengthInBytes(); } if (!ssrcs.empty()) { @@ -890,7 +918,6 @@ } void PeerConnection::closeTracks() { - std::shared_lock lock(mTracksMutex); // read-only iterateTracks(&(shared_ptr<Track> track) { track->close(); }); }
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/queue.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/queue.hpp
Changed
@@ -34,6 +34,7 @@ size_t size() const; // elements size_t amount() const; // amount void push(T element); + bool tryPush(T element); optional<T> pop(); optional<T> peek(); optional<T> exchange(T element); @@ -97,6 +98,16 @@ mQueue.emplace(std::move(element)); } +template <typename T> bool Queue<T>::tryPush(T element) { + std::unique_lock lock(mMutex); + if ((mLimit > 0 && mQueue.size() >= mLimit) || mStopping) + return false; + + mAmount += mAmountFunction(element); + mQueue.emplace(std::move(element)); + return true; +} + template <typename T> optional<T> Queue<T>::pop() { std::unique_lock lock(mMutex); if (mQueue.empty())
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/sctptransport.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/sctptransport.cpp
Changed
@@ -728,7 +728,7 @@ using srs_t = struct sctp_reset_streams; const size_t len = sizeof(srs_t) + sizeof(uint16_t); - byte bufferlen = {}; + alignas(alignof(srs_t)) byte bufferlen = {}; srs_t &srs = *reinterpret_cast<srs_t *>(buffer); srs.srs_flags = SCTP_STREAM_RESET_OUTGOING; srs.srs_number_streams = 1;
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/tlstransport.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/tlstransport.cpp
Changed
@@ -258,8 +258,9 @@ message = *next; if (message->size() > 0) break; - else - t->recv(message); // Pass zero-sized messages through + + t->recv(message); // Pass zero-sized messages through + message.reset(); } } @@ -529,8 +530,9 @@ message = *next; if (message->size() > 0) break; - else - t->recv(message); // Pass zero-sized messages through + + t->recv(message); // Pass zero-sized messages through + message.reset(); } } @@ -622,8 +624,11 @@ if (mIsClient && mHost) { SSL_set_hostflags(mSsl, 0); +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + openssl::check(SSL_set1_dnsname(mSsl, mHost->c_str()), "Failed to set SSL dnsname"); +#else openssl::check(SSL_set1_host(mSsl, mHost->c_str()), "Failed to set SSL host"); - +#endif PLOG_VERBOSE << "Server Name Indication: " << *mHost; SSL_set_tlsext_host_name(mSsl, mHost->c_str()); }
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/track.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/track.cpp
Changed
@@ -73,7 +73,7 @@ triggerClosed(); setMediaHandler(nullptr); resetCallbacks(); - } + } } message_variant Track::trackMessageToVariant(message_ptr message) { @@ -144,9 +144,9 @@ message_vector messages{std::move(message)}; if (auto handler = getMediaHandler()) { try { - handler->incomingChain(messages, this, weak_this = weak_from_this()(message_ptr m) { + handler->incomingChain(messages, weak_this = weak_from_this()(message_ptr m) { if (auto locked = weak_this.lock()) { - transportSend(m); + locked->transportSend(m); } }); } catch (const std::exception &e) { @@ -186,9 +186,9 @@ if (handler) { message_vector messages{std::move(message)}; - handler->outgoingChain(messages, this, weak_this = weak_from_this()(message_ptr m) { + handler->outgoingChain(messages, weak_this = weak_from_this()(message_ptr m) { if (auto locked = weak_this.lock()) { - transportSend(m); + locked->transportSend(m); } });
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/transport.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/transport.cpp
Changed
@@ -38,7 +38,24 @@ Transport::State Transport::state() const { return mState; } -void Transport::onRecv(message_callback callback) { mRecvCallback = std::move(callback); } +void Transport::onRecv(message_callback callback) { + std::vector<message_ptr> pending; + { + std::lock_guard lock(mPendingMutex); + mRecvCallback = std::move(callback); + if (mRecvCallback) + pending = std::move(mPendingRecv); + else + mPendingRecv.clear(); + } + for (auto &msg : pending) { + try { + mRecvCallback(msg); + } catch (const std::exception &e) { + PLOG_WARNING << e.what(); + } + } +} void Transport::onStateChange(state_callback callback) { mStateChangeCallback = std::move(callback); @@ -52,6 +69,17 @@ void Transport::recv(message_ptr message) { try { + std::unique_lock lock(mPendingMutex); + if (!mRecvCallback) { + // No callback registered yet; buffer the message for replay when + // onRecv() is called. Bounded to avoid unbounded growth. + if (mPendingRecv.size() < 8) + mPendingRecv.push_back(std::move(message)); + else + PLOG_WARNING << "dropping incoming message, no receive callback"; + return; + } + lock.unlock(); mRecvCallback(message); } catch (const std::exception &e) { PLOG_WARNING << e.what();
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/transport.hpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/transport.hpp
Changed
@@ -17,6 +17,8 @@ #include <atomic> #include <functional> #include <memory> +#include <mutex> +#include <vector> namespace rtc::impl { @@ -53,6 +55,13 @@ synchronized_callback<message_ptr> mRecvCallback; std::atomic<State> mState = State::Disconnected; + + // Packets received before a callback is registered are held here and + // replayed when onRecv() is first called with a non-null callback. + // This prevents the ICE->DTLS and DTLS->SCTP races where one side + // sends its first packet before the other side has called registerIncoming(). + std::mutex mPendingMutex; + std::vector<message_ptr> mPendingRecv; }; } // namespace rtc::impl
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/websocket.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/websocket.cpp
Changed
@@ -235,30 +235,30 @@ transport->onBufferedAmount(weak_bind(&WebSocket::triggerBufferedAmount, this, _1)); transport->onStateChange(this, weak_this = weak_from_this()(State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (transportState) { - case State::Connected: - if (config.proxyServer) - initProxyTransport(); - else if (mIsSecure) - initTlsTransport(); - else - initWsTransport(); - break; - case State::Failed: - triggerError("TCP connection failed"); - remoteClose(); - break; - case State::Disconnected: - if(state == WebSocket::State::Connecting) - remoteClose(); - break; - default: - // Ignore - break; - } + if(auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case State::Connected: + if (config.proxyServer) + initProxyTransport(); + else if (mIsSecure) + initTlsTransport(); + else + initWsTransport(); + break; + case State::Failed: + triggerError("TCP connection failed"); + remoteClose(); + break; + case State::Disconnected: + if(state == WebSocket::State::Connecting) + remoteClose(); + break; + default: + // Ignore + break; + } + }); }); // WS transport sends a ping on read timeout @@ -289,28 +289,28 @@ throw std::logic_error("No underlying TCP transport for Proxy transport"); auto stateChangeCallback = this, weak_this = weak_from_this()(State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (transportState) { - case State::Connected: - if (mIsSecure) - initTlsTransport(); - else - initWsTransport(); - break; - case State::Failed: - triggerError("Proxy connection failed"); - remoteClose(); - break; - case State::Disconnected: - if(state == WebSocket::State::Connecting) - remoteClose(); - break; - default: - // Ignore - break; - } + if(auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case State::Connected: + if (mIsSecure) + initTlsTransport(); + else + initWsTransport(); + break; + case State::Failed: + triggerError("Proxy connection failed"); + remoteClose(); + break; + case State::Disconnected: + if(state == WebSocket::State::Connecting) + remoteClose(); + break; + default: + // Ignore + break; + } + }); }; auto transport = std::make_shared<HttpProxyTransport>( @@ -348,25 +348,25 @@ } auto stateChangeCallback = this, weak_this = weak_from_this()(State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (transportState) { - case State::Connected: - initWsTransport(); - break; - case State::Failed: - triggerError("TLS connection failed"); - remoteClose(); - break; - case State::Disconnected: - if(state == WebSocket::State::Connecting) - remoteClose(); - break; - default: - // Ignore - break; - } + if(auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case State::Connected: + initWsTransport(); + break; + case State::Failed: + triggerError("TLS connection failed"); + remoteClose(); + break; + case State::Disconnected: + if(state == WebSocket::State::Connecting) + remoteClose(); + break; + default: + // Ignore + break; + } + }); }; bool verify = mHostname.has_value() && !config.disableTlsVerification; @@ -428,28 +428,28 @@ atomic_store(&mWsHandshake, std::make_shared<WsHandshake>()); auto stateChangeCallback = this, weak_this = weak_from_this()(State transportState) { - auto shared_this = weak_this.lock(); - if (!shared_this) - return; - switch (transportState) { - case State::Connected: - if (state == WebSocket::State::Connecting) { - PLOG_DEBUG << "WebSocket open"; - if (changeState(WebSocket::State::Open)) - triggerOpen(); - } - break; - case State::Failed: - triggerError("WebSocket connection failed"); - remoteClose(); - break; - case State::Disconnected: - remoteClose(); - break; - default: - // Ignore - break; - } + if(auto locked = weak_this.lock()) + std::invoke(=() { + switch (transportState) { + case State::Connected: + if (state == WebSocket::State::Connecting) { + PLOG_DEBUG << "WebSocket open"; + if (changeState(WebSocket::State::Open)) + triggerOpen(); + } + break; + case State::Failed: + triggerError("WebSocket connection failed"); + remoteClose(); + break; + case State::Disconnected: + remoteClose(); + break; + default: + // Ignore + break; + } + }); }; auto transport = std::make_shared<WsTransport>(lower, mWsHandshake, config,
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/impl/wstransport.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/impl/wstransport.cpp
Changed
@@ -102,13 +102,12 @@ return; } - ThreadPool::Instance().schedule(std::chrono::seconds(10), - this, weak_this = weak_from_this()() { - if (auto shared_this = weak_this.lock()) { - PLOG_DEBUG << "WebSocket close timeout"; - changeState(State::Disconnected); - } - }); + ThreadPool::Instance().schedule(std::chrono::seconds(10), weak_this = weak_from_this()() { + if (auto locked = weak_this.lock()) { + PLOG_DEBUG << "WebSocket close timeout"; + locked->changeState(State::Disconnected); + } + }); } void WsTransport::incoming(message_ptr message) {
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/pacinghandler.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/pacinghandler.cpp
Changed
@@ -18,41 +18,36 @@ namespace rtc { PacingHandler::PacingHandler(double bitsPerSecond, std::chrono::milliseconds sendInterval) - : mBytesPerSecond(bitsPerSecond / 8), mBudget(0.), mSendInterval(sendInterval){}; + : mBytesPerSecond(bitsPerSecond / 8), mBudget(0.), mSendInterval(sendInterval) {}; void PacingHandler::schedule(const message_callback &send) { - if (mHaveScheduled.exchange(true)) { - return; + if (!mHaveScheduled.exchange(true)) + impl::ThreadPool::Instance().schedule(mSendInterval, + weak_bind(&PacingHandler::run, this, send)); +} + +void PacingHandler::run(const message_callback &send) { + const std::lock_guard<std::mutex> lock(mMutex); + mHaveScheduled.store(false); + + // Update the budget and cap it + auto now = std::chrono::high_resolution_clock::now(); + auto newBudget = std::chrono::duration<double>(now - mLastRun).count() * mBytesPerSecond; + auto maxBudget = std::chrono::duration<double>(mSendInterval).count() * mBytesPerSecond; + mBudget = std::min(mBudget + newBudget, maxBudget); + mLastRun = std::chrono::high_resolution_clock::now(); + + // Send packets while there is budget, allow a single partial packet over budget + while (!mRtpBuffer.empty() && mBudget > 0) { + auto size = int(mRtpBuffer.front()->size()); + send(std::move(mRtpBuffer.front())); + mRtpBuffer.pop(); + mBudget -= size; } - impl::ThreadPool::Instance().schedule(mSendInterval, this, weak_this = weak_from_this(), - send() { - if (auto locked = weak_this.lock()) { - const std::lock_guard<std::mutex> lock(mMutex); - mHaveScheduled.store(false); - - // Update the budget and cap it - auto newBudget = - std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - mLastRun) - .count() * - mBytesPerSecond; - auto maxBudget = std::chrono::duration<double>(mSendInterval).count() * mBytesPerSecond; - mBudget = std::min(mBudget + newBudget, maxBudget); - mLastRun = std::chrono::high_resolution_clock::now(); - - // Send packets while there is budget, allow a single partial packet over budget - while (!mRtpBuffer.empty() && mBudget > 0) { - auto size = int(mRtpBuffer.front()->size()); - send(std::move(mRtpBuffer.front())); - mRtpBuffer.pop(); - mBudget -= size; - } - - if (!mRtpBuffer.empty()) { - schedule(send); - } - } - }); + if (!mRtpBuffer.empty()) { + schedule(send); + } } void PacingHandler::outgoing(message_vector &messages, const message_callback &send) {
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/rembhandler.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/rembhandler.cpp
Changed
@@ -9,6 +9,8 @@ #include "rembhandler.hpp" #include "rtp.hpp" +#include "impl/internals.hpp" + #ifdef _WIN32 #include <winsock2.h> #else @@ -24,15 +26,21 @@ void RembHandler::incoming(message_vector &messages, maybe_unused const message_callback &send) { for (const auto &message : messages) { size_t offset = 0; - while ((sizeof(RtcpHeader) + offset) <= message->size()) { + while (offset + sizeof(RtcpHeader) <= message->size()) { auto header = reinterpret_cast<RtcpHeader *>(message->data() + offset); - uint8_t payload_type = header->payloadType(); + size_t length = header->lengthInBytes(); + if (offset + length > message->size()) + break; - if (payload_type == 206 && header->reportCount() == 15 && header->lengthInBytes() == sizeof(RtcpRemb)) { - auto remb = reinterpret_cast<RtcpRemb *>(message->data() + offset); + if (header->payloadType() == 206 && header->reportCount() == 15 && length >= sizeof(RtcpRemb)) { + if (offset + sizeof(RtcpRemb) > message->size()) + break; - if (remb->_id0 == 'R' && remb->_id1 == 'E' && remb->_id2 == 'M' && remb->_id3 == 'B') { - mOnRemb(remb->getBitrate()); + auto remb = reinterpret_cast<RtcpRemb *>(message->data() + offset); + if (remb->hasValidId()) { + unsigned int bitrate = remb->getBitrate(); + PLOG_DEBUG << "Got REMB, bitrate=" << bitrate; + mOnRemb(bitrate); break; } }
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/rtcpreceivingsession.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/rtcpreceivingsession.cpp
Changed
@@ -15,6 +15,7 @@ #include "impl/logcounter.hpp" #include <cmath> +#include <mutex> #include <utility> #ifdef _WIN32 @@ -26,12 +27,18 @@ namespace rtc { static impl::LogCounter COUNTER_BAD_RTP_HEADER(plog::warning, "Number of malformed RTP headers"); +static impl::LogCounter COUNTER_BAD_RTCP_HEADER(plog::warning, "Number of malformed RTCP headers"); static impl::LogCounter COUNTER_UNKNOWN_PPID(plog::warning, "Number of Unknown PPID messages"); static impl::LogCounter COUNTER_BAD_NOTIF_LEN(plog::warning, "Number of Bad-Lengthed notifications"); static impl::LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning, "Number of unknown SCTP_STATUS errors"); +RtcpReceivingSession::SyncTimestamps RtcpReceivingSession::getSyncTimestamps(){ + std::lock_guard lock(mSyncMutex); + return mSyncTimestamps; +} + void RtcpReceivingSession::incoming(message_vector &messages, const message_callback &send) { message_vector result; for (auto message : messages) { @@ -67,15 +74,34 @@ } case Message::Control: { - auto rr = reinterpret_cast<const RtcpRr *>(message->data()); - if (rr->header.payloadType() == 201) { // RR + if (message->size() < sizeof(RtcpHeader)) { + COUNTER_BAD_RTCP_HEADER++; + PLOG_VERBOSE << "RTCP packet is too small, size=" << message->size(); + continue; + } + auto header = reinterpret_cast<const RtcpHeader *>(message->data()); + if (header->payloadType() == 201) { // RR + if (message->size() < RtcpRr::SizeWithReportBlocks(0)) { + COUNTER_BAD_RTCP_HEADER++; + PLOG_VERBOSE << "RTCP RR is too small, size=" << message->size(); + continue; + } + auto rr = reinterpret_cast<const RtcpRr *>(message->data()); mSsrc = rr->senderSSRC(); rr->log(); - } else if (rr->header.payloadType() == 200) { // SR - mSsrc = rr->senderSSRC(); + } else if (header->payloadType() == 200) { // SR + if (message->size() < RtcpSr::Size(0)) { + COUNTER_BAD_RTCP_HEADER++; + PLOG_VERBOSE << "RTCP SR is too small, size=" << message->size(); + continue; + } auto sr = reinterpret_cast<const RtcpSr *>(message->data()); - mSyncRTPTS = sr->rtpTimestamp(); - mSyncNTPTS = sr->ntpTimestamp(); + mSsrc = sr->senderSSRC(); + { + std::lock_guard lock(mSyncMutex); + mSyncTimestamps.rtpTimestamp = sr->rtpTimestamp(); + mSyncTimestamps.ntpTimestamp = sr->ntpTimestamp(); + } sr->log(); // TODO For the time being, we will send RR's/REMB's when we get an SR @@ -105,7 +131,7 @@ auto message = make_message(RtcpRemb::SizeWithSSRCs(1), Message::Control); auto remb = reinterpret_cast<RtcpRemb *>(message->data()); remb->preparePacket(mSsrc, 1, bitrate); - remb->setSsrc(0, mSsrc); + remb->setSSRC(0, mSsrc); send(message); } @@ -120,7 +146,7 @@ auto lost = 0; if (mReceived > 0) { lost = expected - mReceived; - } + } auto expected_interval = expected - mExpectedPrior; mExpectedPrior = expected; @@ -130,15 +156,17 @@ uint8_t fraction; - if (expected_interval == 0 || lost_interval <= 0) { + if (expected_interval == 0 || lost_interval <= 0) { fraction = 0; - } - else { + } + else { fraction = (lost_interval << 8) / expected_interval; } - - rr->getReportBlock(0)->preparePacket(mSsrc, fraction, lost, uint16_t(mGreatestSeqNo), mMaxSeq, 0, mSyncNTPTS, - lastSrDelay); + auto syncTimestamps = getSyncTimestamps(); + auto reportBlock = rr->getReportBlock(0); + assert(reportBlock); + reportBlock->preparePacket(mSsrc, fraction, lost, uint16_t(mGreatestSeqNo), mMaxSeq, 0, syncTimestamps.ntpTimestamp, + lastSrDelay); rr->log(); send(message); }
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/rtp.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/rtp.cpp
Changed
@@ -183,7 +183,7 @@ setSSRC(in_ssrc); setPacketsLost(fraction, totalPacketsLost); - + // Middle 32 bits of NTP Timestamp // _lastReport = lastSR_NTP >> 16u; setNTPOfSR(uint64_t(lastSR_NTP)); @@ -306,9 +306,19 @@ this->_senderSSRC = htonl(senderSSRC); } -const RtcpReportBlock *RtcpSr::getReportBlock(int num) const { return &_reportBlocks + num; } +const RtcpReportBlock *RtcpSr::getReportBlock(int num) const { + if (num < 0 || num >= int((header.lengthInBytes() - 24) / sizeof(RtcpReportBlock))) + return nullptr; + + return &_reportBlocks + num; +} + +RtcpReportBlock *RtcpSr::getReportBlock(int num) { + if (num < 0 || num >= int((header.lengthInBytes() - 24) / sizeof(RtcpReportBlock))) + return nullptr; -RtcpReportBlock *RtcpSr::getReportBlock(int num) { return &_reportBlocks + num; } + return &_reportBlocks + num; +} size_t RtcpSr::getSize() const { // "length" in packet is one less than the number of 32 bit words in the packet. @@ -333,9 +343,9 @@ << ", RtpTS=" << rtpTimestamp() << ", packetCount=" << packetCount() << ", octetCount=" << octetCount(); - for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { - getReportBlock(i)->log(); - } + for (int i = 0; i < header.reportCount(); i++) + if (const auto *reportBlock = getReportBlock(i)) + reportBlock->log(); } unsigned int RtcpSdesItem::Size(uint8_t textLength) { return textLength + 2; } @@ -420,6 +430,7 @@ return -1; } textsLength.push_back(itemLength); + size += RtcpSdesItem::Size(itemLength); // safely to access next item item = getItem(++i); } @@ -505,9 +516,19 @@ header.prepareHeader(202, chunkCount, length); } -const RtcpReportBlock *RtcpRr::getReportBlock(int num) const { return &_reportBlocks + num; } +const RtcpReportBlock *RtcpRr::getReportBlock(int num) const { + if (num < 0 || num >= int((header.lengthInBytes() - 4) / sizeof(RtcpReportBlock))) + return nullptr; + + return &_reportBlocks + num; +} -RtcpReportBlock *RtcpRr::getReportBlock(int num) { return &_reportBlocks + num; } +RtcpReportBlock *RtcpRr::getReportBlock(int num) { + if (num < 0 || num >= int((header.lengthInBytes() - 4) / sizeof(RtcpReportBlock))) + return nullptr; + + return &_reportBlocks + num; +} size_t RtcpRr::SizeWithReportBlocks(uint8_t reportCount) { return sizeof(header) + 4 + size_t(reportCount) * sizeof(RtcpReportBlock); @@ -538,9 +559,9 @@ PLOG_VERBOSE << "RTCP RR: " << " SSRC=" << ntohl(_senderSSRC); - for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { - getReportBlock(i)->log(); - } + for (int i = 0; i < header.reportCount(); i++) + if (const auto *reportBlock = getReportBlock(i)) + reportBlock->log(); } size_t RtcpRemb::SizeWithSSRCs(int count) { return sizeof(RtcpRemb) + (count - 1) * sizeof(SSRC); } @@ -576,21 +597,56 @@ } // "length" in packet is one less than the number of 32 bit words in the packet. - header.header.setLength(uint16_t((offsetof(RtcpRemb, _ssrc) / sizeof(uint32_t)) - 1 + numSSRC)); + header.header.setLength(uint16_t((offsetof(RtcpRemb, _ssrcs) / sizeof(uint32_t)) + numSSRC - 1)); _bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate); } -void RtcpRemb::setSsrc(int iterator, SSRC newSssrc) { _ssrciterator = htonl(newSssrc); } +SSRC RtcpRemb::getSSRC(int num) const { + if (num < 0 || num >= getSSRCCount()) + throw std::out_of_range("SSRC num out of range"); + return ntohl(_ssrcsnum); +} +void RtcpRemb::setSSRC(int num, SSRC newSsrc) { + if (num < 0 || num >= getSSRCCount()) + throw std::out_of_range("SSRC num out of range"); + _ssrcsnum = htonl(newSsrc); +} -unsigned int RtcpRemb::getNumSSRC() { return ntohl(_bitrate) >> 24u; } +bool RtcpRemb::hasValidId() const { + return _id0 == 'R' && _id1 == 'E' && _id2 == 'M' && _id3 == 'B'; +} -unsigned int RtcpRemb::getBitrate() { +int RtcpRemb::getSSRCCount() const { + return std::min( + int(ntohl(_bitrate) >> 24u), + std::max(int(header.header.length() + 1 - offsetof(RtcpRemb, _ssrcs) / sizeof(uint32_t)), 0)); +} + +unsigned int RtcpRemb::getBitrate() const { uint32_t br = ntohl(_bitrate); uint8_t exp = (br << 8u) >> 26u; return (br & 0x3FFFF) * static_cast<unsigned int>(pow(2, exp)); } +void RtcpRemb::setSsrc(int num, SSRC newSsrc) { + if (num < 0 || num >= getSSRCCount()) + throw std::out_of_range("SSRC num out of range"); + _ssrcsnum = htonl(newSsrc); +} + +unsigned int RtcpRemb::getNumSSRC() const { + return unsigned(getSSRCCount()); +} + +unsigned int RtcpRemb::getNumSSRC() { + return unsigned(getSSRCCount()); +} + +unsigned int RtcpRemb::getBitrate() { + return std::as_const(*this).getBitrate(); +} + unsigned int RtcpPli::Size() { return sizeof(RtcpFbHeader); } void RtcpPli::preparePacket(SSRC messageSSRC) { @@ -640,7 +696,12 @@ return offsetof(RtcpNack, parts) + sizeof(RtcpNackPart) * discreteSeqNoCount; } -unsigned int RtcpNack::getSeqNoCount() { return header.header.length() - 2; } +unsigned int RtcpNack::getSeqNoCount() { + if (header.header.length() < 2) + return 0; + + return header.header.length() - 2; +} void RtcpNack::preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) { header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount)); @@ -677,10 +738,12 @@ size_t RtpRtx::getSize() const { return header.getSize() + sizeof(uint16_t); } size_t RtpRtx::normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) { + if (totalSize < getSize()) + throw std::invalid_argument("Packet size is too small for RTX"); + header.setSeqNumber(getOriginalSeqNo()); header.setSsrc(originalSSRC); header.setPayloadType(originalPayloadType); - // TODO, the -12 is the size of the header (which is variable!) memmove(header.getBody(), getBody(), totalSize - getSize()); return totalSize - 2; }
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/rtpdepacketizer.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/rtpdepacketizer.cpp
Changed
@@ -35,10 +35,16 @@ continue; } - auto pkt = reinterpret_cast<const rtc::RtpHeader *>(message->data()); - auto headerSize = sizeof(rtc::RtpHeader) + pkt->csrcCount() + pkt->getExtensionHeaderSize(); - result.push_back(make_message(message->begin() + headerSize, message->end(), - createFrameInfo(pkt->timestamp(), pkt->payloadType()))); + auto header = reinterpret_cast<const rtc::RtpHeader *>(message->data()); + if (message->size() < header->getSize()) + continue; // truncated header + + auto totalHeaderSize = header->getSize() + header->getExtensionHeaderSize(); + if (message->size() < totalHeaderSize) + continue; // truncated header + + result.push_back(make_message(message->begin() + totalHeaderSize, message->end(), + createFrameInfo(header->timestamp(), header->payloadType()))); } messages.swap(result); @@ -73,6 +79,8 @@ } auto header = reinterpret_cast<const RtpHeader *>(message->data()); + if (message->size() < header->getSize()) + continue; // truncated header if (!mBuffer.empty()) { auto first = *mBuffer.begin();
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/src/rtppacketizer.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/src/rtppacketizer.cpp
Changed
@@ -57,10 +57,14 @@ rtpExtHeaderSize += headerSize + 1; const bool setPlayoutDelay = rtpConfig->playoutDelayId > 0; + const bool setColorSpace = rtpConfig->colorSpaceId > 0; if (setPlayoutDelay) rtpExtHeaderSize += headerSize + 3; + if (setColorSpace) + rtpExtHeaderSize += headerSize + 4; + if (rtpConfig->mid.has_value()) rtpExtHeaderSize += headerSize + rtpConfig->mid->length(); @@ -139,6 +143,16 @@ offset += extHeader->writeHeader( twoByteHeader, offset, rtpConfig->playoutDelayId, data, 3); } + + if (setColorSpace) { + uint8_t range_chr = (rtpConfig->colorRange << 4) + (rtpConfig->colorChromaSitingHorz << 2) + rtpConfig->colorChromaSitingVert; + + byte data = {byte(rtpConfig->colorPrimaries), byte(rtpConfig->colorTransfer), + byte(rtpConfig->colorMatrix), byte(range_chr)}; + + offset += extHeader->writeHeader( + twoByteHeader, offset, rtpConfig->colorSpaceId, data, 4); + } } rtp->preparePacket();
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/test/main.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/test/main.cpp
Changed
@@ -72,7 +72,7 @@ Test("WebRTC broken fingerprint", test_connectivity_fail_on_wrong_fingerprint), Test("pem", test_pem), // TODO: Temporarily disabled as the Open Relay TURN server is unreliable - // new Test("WebRTC TURN connectivity", test_turn_connectivity), + // Test("WebRTC TURN connectivity", test_turn_connectivity), Test("WebRTC negotiated DataChannel", test_negotiated), Test("WebRTC reliability mode", test_reliability), #if RTC_ENABLE_MEDIA @@ -80,7 +80,7 @@ #endif #if RTC_ENABLE_WEBSOCKET // TODO: Temporarily disabled as the echo service is unreliable - // new Test("WebSocket", test_websocket), + // Test("WebSocket", test_websocket), Test("WebSocketServer", test_websocketserver), #endif Test("Cleanup", test_cleanup), @@ -96,6 +96,8 @@ }; int main(int argc, char **argv) { + rtc::SetThreadPoolSize(4); + int success_tests = 0; int failed_tests = 0; steady_clock::time_point startTime, endTime; @@ -118,6 +120,7 @@ cout << "Finished " << success_tests + failed_tests << " tests in " << durationS.count() << "s (" << durationMs.count() << " ms). Succeeded: " << success_tests << ". Failed: " << failed_tests << "." << endl; + /* // Benchmark try {
View file
_service:obs_scm:libdatachannel-0.23.3.obscpio/test/track.cpp -> _service:obs_scm:libdatachannel-0.24.3.obscpio/test/track.cpp
Changed
@@ -137,8 +137,8 @@ media2.setBitrate(3000); media2.addSSRC(2468, "video-send"); - // NOTE: Overwriting the old shared_ptr for t1 will cause it's respective - // track to be dropped (so it's SSRCs won't be on the description next time) + // NOTE: Overwriting the old shared_ptr for t1 will cause the respective + // track to be dropped (so its SSRCs won't be on the description next time) t1 = pc1.addTrack(media2); pc1.setLocalDescription(); @@ -151,14 +151,16 @@ if (!at2 || !at2->isOpen() || !t1->isOpen()) return TestResult(false, "Renegotiated track is not open"); +#if RTC_ENABLE_MEDIA + // RTP test std::vector<std::byte> payload = {std::byte{0}, std::byte{1}, std::byte{2}, std::byte{3}}; std::vector<std::byte> rtpRaw(sizeof(RtpHeader) + payload.size()); auto *rtp = reinterpret_cast<RtpHeader *>(rtpRaw.data()); + rtp->preparePacket(); rtp->setPayloadType(96); rtp->setSeqNumber(1); rtp->setTimestamp(3000); rtp->setSsrc(2468); - rtp->preparePacket(); std::memcpy(rtpRaw.data() + sizeof(RtpHeader), payload.data(), payload.size()); if (!t1->send(rtpRaw.data(), rtpRaw.size())) { @@ -167,7 +169,7 @@ // wait for an RTP packet to be received auto future = recvRtpPromise.get_future(); - if (future.wait_for(5s) == std::future_status::timeout) { + if (future.wait_for(2s) == std::future_status::timeout) { throw runtime_error("Didn't receive RTP packet on pc2"); } @@ -181,6 +183,32 @@ throw runtime_error("Received RTP packet is different than the packet that was sent"); } + // RTCP REMB test + std::promise<unsigned int> rembPromise; + t1->setMediaHandler(make_shared<RembHandler>(&rembPromise(unsigned int bitrate) { + rembPromise.set_value(bitrate); + })); + + std::vector<std::byte> rtcpRembRaw(RtcpRemb::SizeWithSSRCs(2)); + auto *rtcpRemb = reinterpret_cast<RtcpRemb*>(rtcpRembRaw.data()); + rtcpRemb->preparePacket(6666, 2, 1000000); + rtcpRemb->setSSRC(0, 2468); + rtcpRemb->setSSRC(1, 2469); + if (!t2->send(rtcpRembRaw.data(), rtcpRembRaw.size())) { + throw runtime_error("Couldn't send RTCP REMB message"); + } + + auto rembFuture = rembPromise.get_future(); + if (rembFuture.wait_for(2s) == std::future_status::timeout) { + throw runtime_error("Didn't receive REMB message"); + } + + unsigned int bitrate = rembFuture.get(); + if (bitrate != 1000000) { + throw runtime_error("Incorrect bitrate in REMB message"); + } +#endif + // Delay close of peer 2 to check closing works properly pc1.close(); this_thread::sleep_for(1s);
View file
_service:obs_scm:libdatachannel.obsinfo
Changed
@@ -1,4 +1,4 @@ name: libdatachannel -version: 0.23.3 -mtime: 1763340965 -commit: d9391849bdb183854af7d4d92cae8f6a918d7a40 +version: 0.24.3 +mtime: 1778359897 +commit: c6696d157b5612df2a741d9a03b192b47ab6cefb
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.