Projects
Multimedia
libdatachannel
Sign Up
Log In
Username
Password
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 { - cout << endl << "*** Running C API cleanup..." << endl; - rtcCleanup(); - cout << "*** Finished C API cleanup..." << endl; - } catch (const exception &e) { - cerr << "C API cleanup failed: " << e.what() << endl; - return -1; - } -/* - // Benchmark - try { - cout << endl << "*** Running WebRTC benchmark..." << endl; - test_benchmark(); - cout << "*** Finished WebRTC benchmark" << endl; - } catch (const exception &e) { - cerr << "WebRTC benchmark failed: " << e.what() << endl; - std::this_thread::sleep_for(2s); - return -1; + Test("C API cleanup", test_capi_cleanup), +}; + +int main(int argc, char **argv) { + int success_tests = 0; + int failed_tests = 0; + steady_clock::time_point startTime, endTime; + + startTime = steady_clock::now(); + + for (auto test : tests) { + auto res = test.run(); + if (res.success) { + success_tests++; + } else { + failed_tests++; + } } -*/ + + endTime = steady_clock::now(); + + auto durationMs = duration_cast<milliseconds>(endTime - startTime); + auto durationS = duration_cast<seconds>(endTime - startTime); + cout << "Finished " << success_tests + failed_tests << " tests in " << durationS.count() + << "s (" << durationMs.count() << " ms). Succeeded: " << success_tests + << ". Failed: " << failed_tests << "." << endl; + /* + // Benchmark + try { + cout << endl << "*** Running WebRTC benchmark..." << endl; + test_benchmark(); + cout << "*** Finished WebRTC benchmark" << endl; + } catch (const exception &e) { + cerr << "WebRTC benchmark failed: " << e.what() << endl; + std::this_thread::sleep_for(2s); + return -1; + } + */ return 0; }
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
.