Projects
Multimedia
libdatachannel
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
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);
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; + } + }); };
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
.