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 6
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="obs_scm"> <param name="filename">libdatachannel</param> - <param name="revision">222529eb2c8ae44f96462504ae38023f62809cec</param> + <param name="revision">9e6a13abbb6846c003d817d0387b6706466e2b03</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.1.obscpio/.github/workflows/build-nomedia.yml -> _service:obs_scm:libdatachannel-0.23.2.obscpio/.github/workflows/build-nomedia.yml
Changed
@@ -25,7 +25,7 @@ - uses: actions/checkout@v4 - uses: ilammy/msvc-dev-cmd@v1 - name: install packages - run: choco install openssl + run: choco install openssl --version=3.5.2 - name: submodules run: git submodule update --init --recursive --depth 1 - name: cmake
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/.github/workflows/build-openssl.yml -> _service:obs_scm:libdatachannel-0.23.2.obscpio/.github/workflows/build-openssl.yml
Changed
@@ -41,7 +41,7 @@ - uses: actions/checkout@v4 - uses: ilammy/msvc-dev-cmd@v1 - name: install packages - run: choco install openssl + run: choco install openssl --version=3.5.2 - name: submodules run: git submodule update --init --recursive --depth 1 - name: cmake
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/.gitignore -> _service:obs_scm:libdatachannel-0.23.2.obscpio/.gitignore
Changed
@@ -12,4 +12,5 @@ /tests .DS_Store .idea - +# clangd cache +.cache
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/CMakeLists.txt -> _service:obs_scm:libdatachannel-0.23.2.obscpio/CMakeLists.txt
Changed
@@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.13) project(libdatachannel - VERSION 0.23.1 + VERSION 0.23.2 LANGUAGES CXX) set(PROJECT_DESCRIPTION "C/C++ WebRTC network library featuring Data Channels, Media Transport, and WebSockets") @@ -27,6 +27,13 @@ option(SCTP_DEBUG "Enable SCTP debugging output to verbose log" OFF) option(RTC_UPDATE_VERSION_HEADER "Enable updating the version header" OFF) +if(NOT NO_MEDIA AND NOT PREFER_SYSTEM_LIB) + # libsrtp2 v2.7.0 requires cmake >= v3.21.0 + if(CMAKE_VERSION VERSION_LESS 3.21) + message(FATAL_ERROR "CMake >= v3.21 is required to build libdatachannel with media support (with submodules).") + endif() +endif() + if (USE_GNUTLS AND USE_MBEDTLS) message(FATAL_ERROR "Both USE_MBEDTLS and USE_GNUTLS cannot be enabled at the same time") endif() @@ -219,6 +226,10 @@ ${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark.cpp ) +set(TESTS_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/test/test.hpp +) + set(TESTS_UWP_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/Logo.png ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/package.appxManifest @@ -504,6 +515,11 @@ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) +if(MSVC) + install(FILES $<TARGET_PDB_FILE:datachannel> + DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) +endif() + install(FILES ${LIBDATACHANNEL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rtc ) @@ -539,9 +555,9 @@ if(NOT NO_TESTS) if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") # Add resource files needed for UWP apps. - add_executable(datachannel-tests ${TESTS_SOURCES} ${TESTS_UWP_RESOURCES}) + add_executable(datachannel-tests ${TESTS_SOURCES} ${TESTS_HEADERS} ${TESTS_UWP_RESOURCES}) else() - add_executable(datachannel-tests ${TESTS_SOURCES}) + add_executable(datachannel-tests ${TESTS_SOURCES} ${TESTS_HEADERS}) endif() set_target_properties(datachannel-tests PROPERTIES
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/Jamfile -> _service:obs_scm:libdatachannel-0.23.2.obscpio/Jamfile
Changed
@@ -118,7 +118,7 @@ cd $(CWD)/deps/usrsctp mkdir $(BUILD_DIR) cd $(BUILD_DIR) - cmake -G "Visual Studio 16 2019" -Dsctp_werror=0 -Dsctp_build_shared_lib=0 -Dsctp_build_programs=0 -Dsctp_inet=0 -Dsctp_inet6=0 .. + cmake -G "Visual Studio 17 2022" -Dsctp_werror=0 -Dsctp_build_shared_lib=0 -Dsctp_build_programs=0 -Dsctp_inet=0 -Dsctp_inet6=0 .. msbuild usrsctplib.sln /property:Configuration=$(VARIANT) cd %OLDD% cp $(CWD)/deps/usrsctp/$(BUILD_DIR)/usrsctplib/Release/usrsctp.lib $(<) @@ -182,7 +182,7 @@ cd $(CWD)/deps/libjuice mkdir $(BUILD_DIR) cd $(BUILD_DIR) - cmake -G "Visual Studio 16 2019" $(CMAKEOPTS) .. + cmake -G "Visual Studio 17 2022" $(CMAKEOPTS) .. msbuild libjuice.sln /property:Configuration=$(VARIANT) cd %OLDD% cp $(CWD)/deps/libjuice/$(BUILD_DIR)/Release/juice-static.lib $(<)
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/examples/signaling-server-python/signaling-server.py -> _service:obs_scm:libdatachannel-0.23.2.obscpio/examples/signaling-server-python/signaling-server.py
Changed
@@ -22,10 +22,10 @@ clients = {} -async def handle_websocket(websocket, path): +async def handle_websocket(websocket): client_id = None try: - splitted = path.split('/') + splitted = websocket.request.path.split('/') splitted.pop(0) client_id = splitted.pop(0) print('Client {} connected'.format(client_id)) @@ -75,4 +75,4 @@ if __name__ == '__main__': - asyncio.run(main()) + asyncio.run(main()) \ No newline at end of file
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/include/rtc/rtcpreceivingsession.hpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/include/rtc/rtcpreceivingsession.hpp
Changed
@@ -19,6 +19,8 @@ #include <atomic> +#define RTP_SEQ_MOD (1<<16) + namespace rtc { // An RtcpSession can be plugged into a Track to handle the whole RTCP session @@ -40,8 +42,22 @@ void pushRR(const message_callback &send,unsigned int lastSrDelay); void pushPLI(const message_callback &send); + void initSeq(uint16_t seq); + bool updateSeq(uint16_t seq); + SSRC mSsrc = 0; uint32_t mGreatestSeqNo = 0; + uint16_t mMaxSeq = 0; // highest seq. number seen + uint32_t mCycles = 0; // shifted count of seq. number cycles + uint32_t mBaseSeq = 0; // base seq number + uint32_t mBadSeq = 0; // last 'bad' seq number + 1 + uint32_t mProbation = 0; // sequ. packets till source is valid + uint32_t mReceived = 0; // packets received + uint32_t mExpectedPrior = 0; // packet expected at last interval + uint32_t mReceivedPrior = 0; // packet received at last interval + uint32_t mTransit = 0; // relative trans time for prev pkt + uint32_t mJitter = 0; + uint64_t mSyncRTPTS, mSyncNTPTS; std::atomic<unsigned int> mRequestedBitrate = 0;
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/include/rtc/rtp.hpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/include/rtc/rtp.hpp
Changed
@@ -102,7 +102,7 @@ nodiscard uint8_t getFractionLost() const; nodiscard unsigned int getPacketsLostCount() const; - void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets, + void preparePacket(SSRC in_ssrc, uint8_t fraction, unsigned int totalPacketsLost, uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP, uint64_t lastSR_DELAY); void setSSRC(SSRC in_ssrc);
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/include/rtc/version.h -> _service:obs_scm:libdatachannel-0.23.2.obscpio/include/rtc/version.h
Changed
@@ -3,7 +3,7 @@ #define RTC_VERSION_MAJOR 0 #define RTC_VERSION_MINOR 23 -#define RTC_VERSION_PATCH 1 -#define RTC_VERSION "0.23.1" +#define RTC_VERSION_PATCH 2 +#define RTC_VERSION "0.23.2" #endif
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/impl/dtlstransport.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/impl/dtlstransport.cpp
Changed
@@ -33,10 +33,12 @@ if (mPendingRecvCount > 0) return; - if (auto shared_this = weak_from_this().lock()) { - ++mPendingRecvCount; - ThreadPool::Instance().enqueue(&DtlsTransport::doRecv, std::move(shared_this)); - } + ++mPendingRecvCount; + + ThreadPool::Instance().enqueue(weak_this = weak_from_this()() { + if (auto locked = weak_this.lock()) + locked->doRecv(); + }); } #if USE_GNUTLS
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/impl/peerconnection.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/impl/peerconnection.cpp
Changed
@@ -1042,6 +1042,9 @@ if (description.mediaCount() == 0) throw std::logic_error("Local description has no media line"); + // Update the SSRC cache + updateTrackSsrcCache(description); + { // Set as local description std::lock_guard lock(mLocalDescriptionMutex);
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/impl/sctptransport.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/impl/sctptransport.cpp
Changed
@@ -82,7 +82,7 @@ std::shared_mutex mMutex; }; -std::unique_ptr<SctpTransport::InstancesSet> SctpTransport::Instances = std::make_unique<InstancesSet>(); +SctpTransport::InstancesSet* SctpTransport::Instances = nullptr; void SctpTransport::Init() { usrsctp_init(0, SctpTransport::WriteCallback, SctpTransport::DebugCallback); @@ -94,6 +94,8 @@ #ifdef SCTP_DEBUG usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); #endif + + Instances = new InstancesSet; } void SctpTransport::SetSettings(const SctpSettings &s) { @@ -148,6 +150,9 @@ void SctpTransport::Cleanup() { while (usrsctp_finish()) std::this_thread::sleep_for(100ms); + + delete Instances; + Instances = nullptr; } SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &config, Ports ports, @@ -729,15 +734,12 @@ srs.srs_number_streams = 1; srs.srs_stream_list0 = streamId; - mWritten = false; - if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_RESET_STREAMS, &srs, len) == 0) { - std::unique_lock lock(mWriteMutex); // locking before setsockopt might deadlock usrsctp... - mWrittenCondition.wait_for(lock, 1000ms, - &() { return mWritten || state() != State::Connected; }); - } else if (errno == EINVAL) { - PLOG_DEBUG << "SCTP stream " << streamId << " already reset"; - } else { - PLOG_WARNING << "SCTP reset stream " << streamId << " failed, errno=" << errno; + if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_RESET_STREAMS, &srs, len)) { + if (errno == EINVAL) { + PLOG_DEBUG << "SCTP stream " << streamId << " already reset"; + } else { + PLOG_WARNING << "SCTP reset stream " << streamId << " failed, errno=" << errno; + } } }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/impl/sctptransport.hpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/impl/sctptransport.hpp
Changed
@@ -127,7 +127,7 @@ static void DebugCallback(const char *format, ...); class InstancesSet; - static std::unique_ptr<InstancesSet> Instances; + static InstancesSet* Instances; }; } // namespace rtc::impl
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/rtcpreceivingsession.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/rtcpreceivingsession.cpp
Changed
@@ -59,6 +59,9 @@ } mSsrc = rtp->ssrc(); + + updateSeq(rtp->seqNumber()); + result.push_back(std::move(message)); break; } @@ -110,7 +113,31 @@ auto message = make_message(RtcpRr::SizeWithReportBlocks(1), Message::Control); auto rr = reinterpret_cast<RtcpRr *>(message->data()); rr->preparePacket(mSsrc, 1); - rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS, + + // calculate packets lost, packet expected, fraction + auto extended_max = mCycles + mMaxSeq; + auto expected = extended_max - mBaseSeq + 1; + auto lost = 0; + if (mReceived > 0) { + lost = expected - mReceived; + } + + auto expected_interval = expected - mExpectedPrior; + mExpectedPrior = expected; + auto received_interval = mReceived - mReceivedPrior; + mReceivedPrior = mReceived; + auto lost_interval = expected_interval - received_interval; + + uint8_t fraction; + + if (expected_interval == 0 || lost_interval <= 0) { + fraction = 0; + } + else { + fraction = (lost_interval << 8) / expected_interval; + } + + rr->getReportBlock(0)->preparePacket(mSsrc, fraction, lost, uint16_t(mGreatestSeqNo), mMaxSeq, 0, mSyncNTPTS, lastSrDelay); rr->log(); send(message); @@ -128,6 +155,69 @@ send(message); } +void RtcpReceivingSession::initSeq(uint16_t seq) { + mBaseSeq = seq; + mMaxSeq = seq; + mBadSeq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */ + mCycles = 0; + mReceived = 0; + mReceivedPrior = 0; + mExpectedPrior = 0; +} + +bool RtcpReceivingSession::updateSeq(uint16_t seq) { + uint16_t udelta = seq - mMaxSeq; + const int MAX_DROPOUT = 3000; + const int MAX_MISORDER = 100; + const int MIN_SEQUENTIAL = 2; + + /* + * Source is not valid until MIN_SEQUENTIAL packets with + * sequential sequence numbers have been received. + */ + if (mProbation) { + /* packet is in sequence */ + if (seq == mMaxSeq + 1) { + mProbation--; + mMaxSeq = seq; + if (mProbation == 0) { + initSeq(seq); + mReceived++; + return true; + } + } else { + mProbation = MIN_SEQUENTIAL - 1; + mMaxSeq = seq; + } + return false; + } else if (udelta < MAX_DROPOUT) { + /* in order, with permissible gap */ + if (seq < mMaxSeq) { + /* + * Sequence number wrapped - count another 64K cycle. + */ + mCycles += RTP_SEQ_MOD; + } + mMaxSeq = seq; + } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { + /* the sequence number made a very large jump */ + if (seq == mBadSeq) { + /* + * Two sequential packets -- assume that the other side + * restarted without telling us so just re-sync + * (i.e., pretend this was the first packet). + */ + initSeq(seq); + } + else { + mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1); + return false; + } + } + mReceived++; + return true; +} + } // namespace rtc #endif // RTC_ENABLE_MEDIA
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/rtp.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/rtp.cpp
Changed
@@ -174,14 +174,16 @@ SSRC RtcpReportBlock::getSSRC() const { return ntohl(_ssrc); } -void RtcpReportBlock::preparePacket(SSRC in_ssrc, maybe_unused unsigned int packetsLost, - maybe_unused unsigned int totalPackets, +void RtcpReportBlock::preparePacket(SSRC in_ssrc, uint8_t fraction, + uint32_t totalPacketsLost, uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP, uint64_t lastSR_DELAY) { setSeqNo(highestSeqNo, seqNoCycles); setJitter(jitter); setSSRC(in_ssrc); + setPacketsLost(fraction, totalPacketsLost); + // Middle 32 bits of NTP Timestamp // _lastReport = lastSR_NTP >> 16u; setNTPOfSR(uint64_t(lastSR_NTP)); @@ -194,18 +196,18 @@ void RtcpReportBlock::setSSRC(SSRC in_ssrc) { _ssrc = htonl(in_ssrc); } void RtcpReportBlock::setPacketsLost(uint8_t fractionLost, - unsigned int packetsLostCount) { + uint32_t packetsLostCount) { _fractionLostAndPacketsLost = htonl((uint32_t(fractionLost) << 24) | (packetsLostCount & 0xFFFFFF)); } uint8_t RtcpReportBlock::getFractionLost() const { // Fraction lost is expressed as 8-bit fixed point number // In order to get actual lost percentage divide the result by 256 - return _fractionLostAndPacketsLost & 0xFF; + return (uint8_t) ((ntohl(_fractionLostAndPacketsLost) & 0xFF00000) >> 24); } -unsigned int RtcpReportBlock::getPacketsLostCount() const { - return ntohl(_fractionLostAndPacketsLost & 0xFFFFFF00); +uint32_t RtcpReportBlock::getPacketsLostCount() const { + return ntohl(_fractionLostAndPacketsLost) & 0x00FFFFFF; } uint16_t RtcpReportBlock::seqNoCycles() const { return ntohs(_seqNoCycles); } @@ -238,9 +240,8 @@ PLOG_VERBOSE << "RTCP report block: " << "ssrc=" << ntohl(_ssrc) - // TODO: Implement these reports - // << ", fractionLost=" << fractionLost - // << ", packetsLost=" << packetsLost + << ", fractionLost=" << (uint32_t)getFractionLost() + << ", packetsLost=" << getPacketsLostCount() << ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles() << ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR() << ", lastSRDelay=" << delaySinceSR();
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/src/rtppacketizer.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/src/rtppacketizer.cpp
Changed
@@ -74,6 +74,8 @@ if (rtpExtHeaderSize != 0) rtpExtHeaderSize += 4; + // Align the size to the multiple of 4 bytes + // according to RFC 3550, sec. 5.3.1. rtpExtHeaderSize = (rtpExtHeaderSize + 3) & ~3; auto message = make_message(RtpHeaderSize + rtpExtHeaderSize + payload.size());
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/capi_connectivity.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/capi_connectivity.cpp
Changed
@@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "test.hpp" #include <rtc/rtc.h> #include <cstdio> @@ -392,7 +393,8 @@ #include <stdexcept> -void test_capi_connectivity() { +TestResult test_capi_connectivity() { if (test_capi_connectivity_main()) - throw std::runtime_error("Connection failed"); + return TestResult(false, "Connection failed"); + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/capi_track.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/capi_track.cpp
Changed
@@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "test.hpp" #include <rtc/rtc.h> #include <cstdio> @@ -238,7 +239,8 @@ #include <stdexcept> -void test_capi_track() { +TestResult test_capi_track() { if (test_capi_track_main()) - throw std::runtime_error("Connection failed"); + return TestResult(false, "Connection failed"); + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/capi_websocketserver.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/capi_websocketserver.cpp
Changed
@@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "test.hpp" #include <rtc/rtc.h> #if RTC_ENABLE_WEBSOCKET @@ -164,9 +165,10 @@ #include <stdexcept> -void test_capi_websocketserver() { +TestResult test_capi_websocketserver() { if (test_capi_websocketserver_main()) - throw std::runtime_error("WebSocketServer test failed"); + return TestResult(false, "WebSocketServer test failed"); + return TestResult(true); } #endif
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/connectivity.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/connectivity.cpp
Changed
@@ -7,6 +7,7 @@ */ #include "rtc/rtc.hpp" +#include "test.hpp" #include <atomic> #include <chrono> @@ -21,7 +22,13 @@ template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; } -void test_connectivity(bool signal_wrong_fingerprint) { +TestResult test_connectivity(bool); + +TestResult test_connectivity() { return test_connectivity(false); } + +TestResult test_connectivity_fail_on_wrong_fingerprint() { return test_connectivity(true); } + +TestResult test_connectivity(bool signal_wrong_fingerprint) { InitLogger(LogLevel::Debug); Configuration config1; @@ -128,7 +135,7 @@ auto dc1 = pc1.createDataChannel("test"); if (dc1->id().has_value()) - throw std::runtime_error("DataChannel stream id assigned before connection"); + return TestResult(false, "DataChannel stream id assigned before connection"); dc1->onOpen(wdc1 = make_weak_ptr(dc1)() { if (auto dc1 = wdc1.lock()) { @@ -152,30 +159,35 @@ this_thread::sleep_for(1s); if (pc1.state() != PeerConnection::State::Connected || - pc2.state() != PeerConnection::State::Connected) - throw runtime_error("PeerConnection is not connected"); + pc2.state() != PeerConnection::State::Connected) { + if (signal_wrong_fingerprint) { + return TestResult(true); + } else { + return TestResult(false, "PeerConnection is not connected"); + } + } if ((pc1.iceState() != PeerConnection::IceState::Connected && pc1.iceState() != PeerConnection::IceState::Completed) || (pc2.iceState() != PeerConnection::IceState::Connected && pc2.iceState() != PeerConnection::IceState::Completed)) - throw runtime_error("ICE is not connected"); + return TestResult(false, "ICE is not connected"); if (!adc2 || !adc2->isOpen() || !dc1->isOpen()) - throw runtime_error("DataChannel is not open"); + return TestResult(false, "DataChannel is not open"); if (adc2->label() != "test") - throw runtime_error("Wrong DataChannel label"); + return TestResult(false, "Wrong DataChannel label"); if (dc1->maxMessageSize() != CUSTOM_MAX_MESSAGE_SIZE || dc2->maxMessageSize() != CUSTOM_MAX_MESSAGE_SIZE) - throw runtime_error("DataChannel max message size is incorrect"); + return TestResult(false, "DataChannel max message size is incorrect"); if (!dc1->id().has_value()) - throw runtime_error("DataChannel stream id is not assigned"); + return TestResult(false, "DataChannel stream id is not assigned"); if (dc1->id().value() != adc2->id().value()) - throw runtime_error("DataChannel stream ids do not match"); + return TestResult(false, "DataChannel stream ids do not match"); if (auto addr = pc1.localAddress()) cout << "Local address 1: " << *addr << endl; @@ -244,16 +256,16 @@ this_thread::sleep_for(1s); if (!asecond2 || !asecond2->isOpen() || !second1->isOpen()) - throw runtime_error("Second DataChannel is not open"); + return TestResult(false, "Second DataChannel is not open"); if (asecond2->label() != "second") - throw runtime_error("Wrong second DataChannel label"); + return TestResult(false, "Wrong second DataChannel label"); if (!second2->id().has_value() || !asecond2->id().has_value()) - throw runtime_error("Second DataChannel stream id is not assigned"); + return TestResult(false, "Second DataChannel stream id is not assigned"); if (second2->id().value() != asecond2->id().value()) - throw runtime_error("Second DataChannel stream ids do not match"); + return TestResult(false, "Second DataChannel stream ids do not match"); // Delay close of peer 2 to check closing works properly pc1.close(); @@ -261,7 +273,7 @@ pc2.close(); this_thread::sleep_for(1s); - cout << "Success" << endl; + return TestResult(true); } const char* key_pem = @@ -284,7 +296,7 @@ "Ma9ayzQy\n" "-----END CERTIFICATE-----\n"; -void test_pem() { +TestResult test_pem() { InitLogger(LogLevel::Debug); Configuration config1; @@ -310,8 +322,9 @@ cout << "Fingerprint: " << f << endl; - if (f != "07:E5:6F:2A:1A:0C:2C:32:0E:C1:C3:9C:34:5A:78:4E:A5:8B:32:05:D1:57:D6:F4:E7:02:41:12:E6:01:C6:8F") - throw runtime_error("The fingerprint of the specified certificate do not match"); + if (f != "07:E5:6F:2A:1A:0C:2C:32:0E:C1:C3:9C:34:5A:78:4E:A5:8B:32:05:D1:57:D6:F4:E7:02:41:12:" + "E6:01:C6:8F") + return TestResult(false, "The fingerprint of the specified certificate do not match"); - cout << "Success" << endl; + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/main.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/main.cpp
Changed
@@ -10,22 +10,29 @@ #include <iostream> #include <thread> +#include "test.hpp" #include <rtc/rtc.hpp> using namespace std; using namespace chrono_literals; -void test_connectivity(bool signal_wrong_fingerprint); -void test_pem(); -void test_negotiated(); -void test_reliability(); -void test_turn_connectivity(); -void test_track(); -void test_capi_connectivity(); -void test_capi_track(); -void test_websocket(); -void test_websocketserver(); -void test_capi_websocketserver(); +using chrono::duration_cast; +using chrono::milliseconds; +using chrono::seconds; +using chrono::steady_clock; + +TestResult test_connectivity(); +TestResult test_connectivity_fail_on_wrong_fingerprint(); +TestResult test_pem(); +TestResult test_negotiated(); +TestResult test_reliability(); +TestResult test_turn_connectivity(); +TestResult test_track(); +TestResult test_capi_connectivity(); +TestResult test_capi_track(); +TestResult test_websocket(); +TestResult test_websocketserver(); +TestResult test_capi_websocketserver(); size_t benchmark(chrono::milliseconds duration); void test_benchmark() { @@ -39,149 +46,89 @@ throw runtime_error("Goodput is too low"); } -int main(int argc, char **argv) { - // C++ API tests +TestResult test_cleanup() { try { - cout << endl << "*** Running WebRTC connectivity test..." << endl; - test_connectivity(false); - cout << "*** Finished WebRTC connectivity test" << endl; + // Every created object must have been destroyed, otherwise the wait will block + if (rtc::Cleanup().wait_for(10s) == future_status::timeout) + return TestResult(false, "timeout"); + return TestResult(true); } catch (const exception &e) { - cerr << "WebRTC connectivity test failed: " << e.what() << endl; - return -1; - } - try { - cout << endl << "*** Running WebRTC broken fingerprint test..." << endl; - test_connectivity(true); - cerr << "WebRTC connectivity test failed to detect broken fingerprint" << endl; - return -1; - } catch (const exception &) { + return TestResult(false, e.what()); } +} +TestResult test_capi_cleanup() { try { - cout << endl << "*** Running pem test..." << endl; - test_pem(); + rtcCleanup(); + return TestResult(true); } catch (const exception &e) { - cerr << "pem test failed: " << e.what() << endl; - return -1; + return TestResult(false, e.what()); } +} -// TODO: Temporarily disabled as the Open Relay TURN server is unreliable -/* - try { - cout << endl << "*** Running WebRTC TURN connectivity test..." << endl; - test_turn_connectivity(); - cout << "*** Finished WebRTC TURN connectivity test" << endl; - } catch (const exception &e) { - cerr << "WebRTC TURN connectivity test failed: " << e.what() << endl; - return -1; - } -*/ - try { - cout << endl << "*** Running WebRTC negotiated DataChannel test..." << endl; - test_negotiated(); - cout << "*** Finished WebRTC negotiated DataChannel test" << endl; - } catch (const exception &e) { - cerr << "WebRTC negotiated DataChannel test failed: " << e.what() << endl; - return -1; - } - try { - cout << endl << "*** Running WebRTC reliability mode test..." << endl; - test_reliability(); - cout << "*** Finished WebRTC reliaility mode test" << endl; - } catch (const exception &e) { - cerr << "WebRTC reliability test failed: " << e.what() << endl; - return -1; - } +static const vector<Test> tests = { + // C++ API tests + Test("WebRTC connectivity", test_connectivity), + 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 negotiated DataChannel", test_negotiated), + Test("WebRTC reliability mode", test_reliability), #if RTC_ENABLE_MEDIA - try { - cout << endl << "*** Running WebRTC Track test..." << endl; - test_track(); - cout << "*** Finished WebRTC Track test" << endl; - } catch (const exception &e) { - cerr << "WebRTC Track test failed: " << e.what() << endl; - return -1; - } + Test("WebRTC track", test_track), #endif #if RTC_ENABLE_WEBSOCKET -// TODO: Temporarily disabled as the echo service is unreliable -/* - try { - cout << endl << "*** Running WebSocket test..." << endl; - test_websocket(); - cout << "*** Finished WebSocket test" << endl; - } catch (const exception &e) { - cerr << "WebSocket test failed: " << e.what() << endl; - return -1; - } -*/ - try { - cout << endl << "*** Running WebSocketServer test..." << endl; - test_websocketserver(); - cout << "*** Finished WebSocketServer test" << endl; - } catch (const exception &e) { - cerr << "WebSocketServer test failed: " << e.what() << endl; - return -1; - } + // TODO: Temporarily disabled as the echo service is unreliable + // new Test("WebSocket", test_websocket), + Test("WebSocketServer", test_websocketserver), #endif - try { - // Every created object must have been destroyed, otherwise the wait will block - cout << endl << "*** Running cleanup..." << endl; - if(rtc::Cleanup().wait_for(10s) == future_status::timeout) - throw std::runtime_error("Timeout"); - cout << "*** Finished cleanup..." << endl; - } catch (const exception &e) { - cerr << "Cleanup failed: " << e.what() << endl; - return -1; - } - - // C API tests - try { - cout << endl << "*** Running WebRTC C API connectivity test..." << endl; - test_capi_connectivity(); - cout << "*** Finished WebRTC C API connectivity test" << endl; - } catch (const exception &e) { - cerr << "WebRTC C API connectivity test failed: " << e.what() << endl; - return -1; - } + Test("Cleanup", test_cleanup), + // C API tests + Test("WebRTC C API connectivity", test_capi_connectivity), #if RTC_ENABLE_MEDIA - try { - cout << endl << "*** Running WebRTC C API track test..." << endl; - test_capi_track(); - cout << "*** Finished WebRTC C API track test" << endl; - } catch (const exception &e) { - cerr << "WebRTC C API track test failed: " << e.what() << endl; - return -1; - } + Test("WebRTC C API track", test_capi_track), #endif #if RTC_ENABLE_WEBSOCKET - try { - cout << endl << "*** Running WebSocketServer C API test..." << endl; - test_capi_websocketserver(); - cout << "*** Finished WebSocketServer C API test" << endl; - } catch (const exception &e) { - cerr << "WebSocketServer C API test failed: " << e.what() << endl; - return -1; - } + Test("WebSocketServer C API", test_capi_websocketserver), #endif - try {
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/negotiated.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/negotiated.cpp
Changed
@@ -7,6 +7,7 @@ */ #include "rtc/rtc.hpp" +#include "test.hpp" #include <atomic> #include <chrono> @@ -17,7 +18,7 @@ using namespace rtc; using namespace std; -void test_negotiated() { +TestResult test_negotiated() { InitLogger(LogLevel::Debug); Configuration config1; @@ -66,10 +67,10 @@ if (pc1.state() != PeerConnection::State::Connected || pc2.state() != PeerConnection::State::Connected) - throw runtime_error("PeerConnection is not connected"); + return TestResult(false, "PeerConnection is not connected"); if (!negotiated1->isOpen() || !negotiated2->isOpen()) - throw runtime_error("Negotiated DataChannel is not open"); + return TestResult(false, "Negotiated DataChannel is not open"); std::atomic<bool> received = false; negotiated2->onMessage(&received(const variant<binary, string> &message) { @@ -87,7 +88,7 @@ this_thread::sleep_for(1s); if (!received) - throw runtime_error("Negotiated DataChannel failed"); + return TestResult(false, "Negotiated DataChannel failed"); // Delay close of peer 2 to check closing works properly pc1.close(); @@ -95,5 +96,5 @@ pc2.close(); this_thread::sleep_for(1s); - cout << "Success" << endl; + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/reliability.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/reliability.cpp
Changed
@@ -7,6 +7,7 @@ */ #include "rtc/rtc.hpp" +#include "test.hpp" #include <atomic> #include <chrono> @@ -17,7 +18,7 @@ using namespace rtc; using namespace std; -void test_reliability() { +TestResult test_reliability() { InitLogger(LogLevel::Debug); Configuration config1; @@ -114,15 +115,15 @@ if (pc1.state() != PeerConnection::State::Connected || pc2.state() != PeerConnection::State::Connected) - throw runtime_error("PeerConnection is not connected"); + return TestResult(false, "PeerConnection is not connected"); if (failed) - throw runtime_error("Incorrect reliability settings"); + return TestResult(false, "Incorrect reliability settings"); if (count != 4) - throw runtime_error("Some DataChannels are not open"); + return TestResult(false, "Some DataChannels are not open"); pc1.close(); - cout << "Success" << endl; + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.2.obscpio/test/test.hpp
Added
@@ -0,0 +1,40 @@ +/** + * Copyright (c) 2025 Michal Sledz + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <functional> +#include <iostream> + +using namespace std; + +class TestResult { +public: + bool success; + string err_reason; + + TestResult(bool success, string err_reason = "") : success(success), err_reason(err_reason) {} +}; + +class Test { +public: + string name; + function<TestResult(void)> f; + + Test(string name, std::function<TestResult(void)> testFunc) : name(name), f(testFunc) {} + + TestResult run() { + cout << endl << "*** Running " << name << " test" << endl; + TestResult res = this->f(); + if (res.success) { + cout << "*** Finished " << name << " test" << endl; + } else { + cerr << name << " test failed. Reason: " << res.err_reason << endl; + } + + return res; + } +};
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/track.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/track.cpp
Changed
@@ -7,9 +7,12 @@ */ #include "rtc/rtc.hpp" +#include "rtc/rtp.hpp" +#include "test.hpp" #include <atomic> -#include <chrono> +#include <cstring> +#include <future> #include <iostream> #include <memory> #include <thread> @@ -19,7 +22,7 @@ template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; } -void test_track() { +TestResult test_track() { InitLogger(LogLevel::Debug); Configuration config1; @@ -71,7 +74,8 @@ shared_ptr<Track> t2; string newTrackMid; - pc2.onTrack(&t2, &newTrackMid(shared_ptr<Track> t) { + std::promise<rtc::binary> recvRtpPromise; + pc2.onTrack(&t2, &newTrackMid, &recvRtpPromise(shared_ptr<Track> t) { string mid = t->mid(); cout << "Track 2: Received track with mid \"" << mid << "\"" << endl; if (mid != newTrackMid) { @@ -84,6 +88,13 @@ t->onClosed( mid() { cout << "Track 2: Track with mid \"" << mid << "\" is closed" << endl; }); + t->onMessage( + &recvRtpPromise(rtc::binary message) { + // This is an RTP packet + recvRtpPromise.set_value(message); + }, + nullptr); + std::atomic_store(&t2, t); }); @@ -99,7 +110,7 @@ const auto mediaSdp2 = string(Description::Media(mediaSdp1)); if (mediaSdp2 != mediaSdp1) { cout << mediaSdp2 << endl; - throw runtime_error("Media description parsing test failed"); + return TestResult(false, "Media description parsing test failed"); } auto t1 = pc1.addTrack(media); @@ -113,10 +124,10 @@ if (pc1.state() != PeerConnection::State::Connected || pc2.state() != PeerConnection::State::Connected) - throw runtime_error("PeerConnection is not connected"); + return TestResult(false, "PeerConnection is not connected"); if (!at2 || !at2->isOpen() || !t1->isOpen()) - throw runtime_error("Track is not open"); + return TestResult(false, "Track is not open"); // Test renegotiation newTrackMid = "added"; @@ -138,9 +149,37 @@ this_thread::sleep_for(1s); if (!at2 || !at2->isOpen() || !t1->isOpen()) - throw runtime_error("Renegotiated track is not open"); + return TestResult(false, "Renegotiated track is not open"); + + 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->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())) { + throw runtime_error("Couldn't send RTP packet"); + } + + // wait for an RTP packet to be received + auto future = recvRtpPromise.get_future(); + if (future.wait_for(5s) == std::future_status::timeout) { + throw runtime_error("Didn't receive RTP packet on pc2"); + } - // TODO: Test sending RTP packets in track + auto receivedRtpRaw = future.get(); + if (receivedRtpRaw.empty()) { + throw runtime_error("Didn't receive RTP packet on pc2"); + } + + if (receivedRtpRaw.size() != rtpRaw.size() || + memcmp(receivedRtpRaw.data(), rtpRaw.data(), rtpRaw.size()) != 0) { + throw runtime_error("Received RTP packet is different than the packet that was sent"); + } // Delay close of peer 2 to check closing works properly pc1.close(); @@ -149,7 +188,7 @@ this_thread::sleep_for(1s); if (!t1->isClosed() || !t2->isClosed()) - throw runtime_error("Track is not closed"); + return TestResult(false, "Track is not closed"); - cout << "Success" << endl; + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/turn_connectivity.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/turn_connectivity.cpp
Changed
@@ -7,6 +7,7 @@ */ #include "rtc/rtc.hpp" +#include "test.hpp" #include <atomic> #include <chrono> @@ -19,7 +20,7 @@ template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; } -void test_turn_connectivity() { +TestResult test_turn_connectivity() { InitLogger(LogLevel::Debug); Configuration config1; @@ -133,16 +134,16 @@ if (pc1.state() != PeerConnection::State::Connected || pc2.state() != PeerConnection::State::Connected) - throw runtime_error("PeerConnection is not connected"); + return TestResult(false, "PeerConnection is not connected"); if ((pc1.iceState() != PeerConnection::IceState::Connected && pc1.iceState() != PeerConnection::IceState::Completed) || (pc2.iceState() != PeerConnection::IceState::Connected && pc2.iceState() != PeerConnection::IceState::Completed)) - throw runtime_error("ICE is not connected"); + return TestResult(false, "ICE is not connected"); if (!adc2 || !adc2->isOpen() || !dc1->isOpen()) - throw runtime_error("DataChannel is not open"); + return TestResult(false, "DataChannel is not open"); if (auto addr = pc1.localAddress()) cout << "Local address 1: " << *addr << endl; @@ -155,13 +156,13 @@ Candidate local, remote; if (!pc1.getSelectedCandidatePair(&local, &remote)) - throw runtime_error("getSelectedCandidatePair failed"); + return TestResult(false, "getSelectedCandidatePair failed"); cout << "Local candidate 1: " << local << endl; cout << "Remote candidate 1: " << remote << endl; if (local.type() != Candidate::Type::Relayed) - throw runtime_error("Connection is not relayed as expected"); + return TestResult(false, "Connection is not relayed as expected"); // Try to open a second data channel with another label shared_ptr<DataChannel> second2; @@ -214,7 +215,7 @@ this_thread::sleep_for(1s); if (!asecond2 || !asecond2->isOpen() || !second1->isOpen()) - throw runtime_error("Second DataChannel is not open"); + return TestResult(false, "Second DataChannel is not open"); // Try to open a negotiated channel DataChannelInit init; @@ -224,7 +225,7 @@ auto negotiated2 = pc2.createDataChannel("negoctated", init); if (!negotiated1->isOpen() || !negotiated2->isOpen()) - throw runtime_error("Negotiated DataChannel is not open"); + return TestResult(false, "Negotiated DataChannel is not open"); std::atomic<bool> received = false; negotiated2->onMessage(&received(const variant<binary, string> &message) { @@ -242,7 +243,7 @@ this_thread::sleep_for(1s); if (!received) - throw runtime_error("Negotiated DataChannel failed"); + return TestResult(false, "Negotiated DataChannel failed"); // Delay close of peer 2 to check closing works properly pc1.close(); @@ -250,5 +251,5 @@ pc2.close(); this_thread::sleep_for(1s); - cout << "Success" << endl; + return TestResult(true); }
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/websocket.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/websocket.cpp
Changed
@@ -7,6 +7,7 @@ */ #include "rtc/rtc.hpp" +#include "test.hpp" #if RTC_ENABLE_WEBSOCKET @@ -21,7 +22,7 @@ template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; } -void test_websocket() { +TestResult test_websocket() { InitLogger(LogLevel::Debug); const string myMessage = "Hello world from libdatachannel"; @@ -57,15 +58,15 @@ this_thread::sleep_for(1s); if (!ws.isOpen()) - throw runtime_error("WebSocket is not open"); + return TestResult(false, "WebSocket is not open"); if (!received) - throw runtime_error("Expected message not received"); + return TestResult(false, "Expected message not received"); ws.close(); this_thread::sleep_for(1s); - cout << "Success" << endl; + return TestResult(true); } #endif
View file
_service:obs_scm:libdatachannel-0.23.1.obscpio/test/websocketserver.cpp -> _service:obs_scm:libdatachannel-0.23.2.obscpio/test/websocketserver.cpp
Changed
@@ -7,6 +7,7 @@ */ #include "rtc/rtc.hpp" +#include "test.hpp" #if RTC_ENABLE_WEBSOCKET @@ -21,7 +22,7 @@ template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; } -void test_websocketserver() { +TestResult test_websocketserver() { InitLogger(LogLevel::Debug); WebSocketServer::Configuration serverConfig; @@ -38,22 +39,20 @@ cout << "WebSocketServer: Client connection received" << endl; client = incoming; - if(auto addr = client->remoteAddress()) + if (auto addr = client->remoteAddress()) cout << "WebSocketServer: Client remote address is " << *addr << endl; client->onOpen(wclient = make_weak_ptr(client)() { cout << "WebSocketServer: Client connection open" << endl; - if(auto client = wclient.lock()) - if(auto path = client->path()) + if (auto client = wclient.lock()) + if (auto path = client->path()) cout << "WebSocketServer: Requested path is " << *path << endl; }); - client->onClosed(() { - cout << "WebSocketServer: Client connection closed" << endl; - }); + client->onClosed(() { cout << "WebSocketServer: Client connection closed" << endl; }); client->onMessage(wclient = make_weak_ptr(client)(variant<binary, string> message) { - if(auto client = wclient.lock()) + if (auto client = wclient.lock()) client->send(std::move(message)); }); }); @@ -81,8 +80,7 @@ cout << "WebSocket: Received expected message" << endl; else cout << "WebSocket: Received UNEXPECTED message" << endl; - } - else { + } else { binary bin = std::move(get<binary>(message)); if ((maxSizeReceived = (bin.size() == 1000))) cout << "WebSocket: Received large message truncated at max size" << endl; @@ -98,10 +96,10 @@ this_thread::sleep_for(1s); if (!ws.isOpen()) - throw runtime_error("WebSocket is not open"); + return TestResult(false, "WebSocket is not open"); if (!received || !maxSizeReceived) - throw runtime_error("Expected messages not received"); + return TestResult(false, "Expected messages not received"); ws.close(); this_thread::sleep_for(1s); @@ -109,7 +107,7 @@ server.stop(); this_thread::sleep_for(1s); - cout << "Success" << endl; + return TestResult(true); } #endif
View file
_service:obs_scm:libdatachannel.obsinfo
Changed
@@ -1,4 +1,4 @@ name: libdatachannel -version: 0.23.1 -mtime: 1750930494 -commit: 222529eb2c8ae44f96462504ae38023f62809cec +version: 0.23.2 +mtime: 1757111697 +commit: 9e6a13abbb6846c003d817d0387b6706466e2b03
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
.