diff --git a/.gitignore b/.gitignore index cfb24dd..2ecbab1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ node_modules/ *.a *.so compile_commands.json -tests +/tests .DS_Store .idea diff --git a/CMakeLists.txt b/CMakeLists.txt index e76c5e7..14bce3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.7) project(libdatachannel - VERSION 0.11.0 + VERSION 0.11.1 LANGUAGES CXX) set(PROJECT_DESCRIPTION "WebRTC Data Channels Library") @@ -135,6 +135,24 @@ set(TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark.cpp ) +set(TESTS_UWP_RESOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/Logo.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/package.appxManifest + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/SmallLogo.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/SmallLogo44x44.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/SplashScreen.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/StoreLogo.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/Windows_TemporaryKey.pfx) + +set(BENCHMARK_UWP_RESOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/Logo.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/package.appxManifest + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/SmallLogo.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/SmallLogo44x44.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/SplashScreen.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/StoreLogo.png + ${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/Windows_TemporaryKey.pfx) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads REQUIRED) @@ -292,24 +310,30 @@ endif() # Tests if(NOT NO_TESTS) - add_executable(datachannel-tests ${TESTS_SOURCES}) + if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") + # Add resource files needed for UWP apps. + add_executable(datachannel-tests ${TESTS_SOURCES} ${TESTS_UWP_RESOURCES}) + else() + add_executable(datachannel-tests ${TESTS_SOURCES}) + endif() set_target_properties(datachannel-tests PROPERTIES VERSION ${PROJECT_VERSION} CXX_STANDARD 17) - if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") # Prevent a bug in manifest generation for UWP - set_target_properties(datachannel-tests PROPERTIES OUTPUT_NAME tests) - endif() + set_target_properties(datachannel-tests PROPERTIES OUTPUT_NAME tests) target_include_directories(datachannel-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_link_libraries(datachannel-tests datachannel) # Benchmark - add_executable(datachannel-benchmark test/benchmark.cpp) + if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") + # Add resource files needed for UWP apps. + add_executable(datachannel-benchmark test/benchmark.cpp ${BENCHMARK_UWP_RESOURCES}) + else() + add_executable(datachannel-benchmark test/benchmark.cpp) + endif() set_target_properties(datachannel-benchmark PROPERTIES VERSION ${PROJECT_VERSION} CXX_STANDARD 17) - if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") # Prevent a bug in manifest generation for UWP - set_target_properties(datachannel-benchmark PROPERTIES OUTPUT_NAME benchmark) - endif() + set_target_properties(datachannel-benchmark PROPERTIES OUTPUT_NAME benchmark) target_compile_definitions(datachannel-benchmark PRIVATE BENCHMARK_MAIN=1) target_include_directories(datachannel-benchmark PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_link_libraries(datachannel-benchmark datachannel) diff --git a/examples/streamer/client.js b/examples/streamer/client.js index 6d040cd..1ba4b8c 100644 --- a/examples/streamer/client.js +++ b/examples/streamer/client.js @@ -54,12 +54,10 @@ function createPeerConnection() { // connect audio / video pc.addEventListener('track', function (evt) { - if (evt.track.kind == 'video') { - document.getElementById('media').style.display = 'block'; - document.getElementById('video').srcObject = evt.streams[0]; - } else { - document.getElementById('audio').srcObject = evt.streams[0]; - } + document.getElementById('media').style.display = 'block'; + const videoTag = document.getElementById('video'); + videoTag.srcObject = evt.streams[0]; + videoTag.play(); }); let time_start = null; diff --git a/examples/streamer/index.html b/examples/streamer/index.html index 0e28a24..ab7184c 100644 --- a/examples/streamer/index.html +++ b/examples/streamer/index.html @@ -52,7 +52,6 @@ diff --git a/examples/streamer/main.cpp b/examples/streamer/main.cpp index 126aa20..6dac153 100644 --- a/examples/streamer/main.cpp +++ b/examples/streamer/main.cpp @@ -214,7 +214,7 @@ int main(int argc, char **argv) try { shared_ptr addVideo(const shared_ptr pc, const uint8_t payloadType, const uint32_t ssrc, const string cname, const string msid, const function onOpen) { auto video = Description::Video(cname); video.addH264Codec(payloadType); - video.addSSRC(ssrc, cname, msid); + video.addSSRC(ssrc, cname, msid, cname); auto track = pc->addTrack(video); // create RTP configuration auto rtpConfig = shared_ptr(new RtpPacketizationConfig(ssrc, cname, payloadType, H264RtpPacketizer::defaultClockRate)); @@ -238,7 +238,7 @@ shared_ptr addVideo(const shared_ptr pc, const shared_ptr addAudio(const shared_ptr pc, const uint8_t payloadType, const uint32_t ssrc, const string cname, const string msid, const function onOpen) { auto audio = Description::Audio(cname); audio.addOpusCodec(payloadType); - audio.addSSRC(ssrc, cname, msid); + audio.addSSRC(ssrc, cname, msid, cname); auto track = pc->addTrack(audio); // create RTP configuration auto rtpConfig = shared_ptr(new RtpPacketizationConfig(ssrc, cname, payloadType, OpusRtpPacketizer::defaultClockRate)); diff --git a/include/rtc/configuration.hpp b/include/rtc/configuration.hpp index d22c18e..0c9693e 100644 --- a/include/rtc/configuration.hpp +++ b/include/rtc/configuration.hpp @@ -44,7 +44,7 @@ struct RTC_CPP_EXPORT IceServer { RelayType relayType_ = RelayType::TurnUdp); string hostname; - string service; + uint16_t port; Type type; string username; string password; @@ -54,11 +54,11 @@ struct RTC_CPP_EXPORT IceServer { struct RTC_CPP_EXPORT ProxyServer { enum class Type { None = 0, Socks5, Http, Last = Http }; - ProxyServer(Type type_, string ip_, uint16_t port_, string username_ = "", + ProxyServer(Type type_, string hostname_, uint16_t port_, string username_ = "", string password_ = ""); Type type; - string ip; + string hostname; uint16_t port; string username; string password; diff --git a/include/rtc/description.hpp b/include/rtc/description.hpp index 81d3589..a09c91b 100644 --- a/include/rtc/description.hpp +++ b/include/rtc/description.hpp @@ -141,9 +141,9 @@ public: void removeFormat(const string &fmt); void addSSRC(uint32_t ssrc, std::optional name, - std::optional msid = nullopt); + std::optional msid = nullopt, std::optional trackID = nullopt); void replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, std::optional name, - std::optional msid = nullopt); + std::optional msid = nullopt, std::optional trackID = nullopt); bool hasSSRC(uint32_t ssrc); std::vector getSSRCs(); diff --git a/include/rtc/h264rtppacketizer.hpp b/include/rtc/h264rtppacketizer.hpp index 98d1156..f3376aa 100644 --- a/include/rtc/h264rtppacketizer.hpp +++ b/include/rtc/h264rtppacketizer.hpp @@ -16,8 +16,8 @@ * along with this program; If not, see . */ -#ifndef H264RtpPacketizer_hpp -#define H264RtpPacketizer_hpp +#ifndef H264_RTP_PACKETIZER_H +#define H264_RTP_PACKETIZER_H #if RTC_ENABLE_MEDIA @@ -64,4 +64,4 @@ private: #endif /* RTC_ENABLE_MEDIA */ -#endif /* H264RtpPacketizer_hpp */ +#endif /* H264_RTP_PACKETIZER_H */ diff --git a/include/rtc/nalunit.hpp b/include/rtc/nalunit.hpp index 5970881..1012bf0 100644 --- a/include/rtc/nalunit.hpp +++ b/include/rtc/nalunit.hpp @@ -16,8 +16,8 @@ * along with this program; If not, see . */ -#ifndef NalUnit_hpp -#define NalUnit_hpp +#ifndef NAL_UNIT_H +#define NAL_UNIT_H #if RTC_ENABLE_MEDIA @@ -152,4 +152,4 @@ public: #endif /* RTC_ENABLE_MEDIA */ -#endif /* NalUnit_hpp */ +#endif /* NAL_UNIT_H */ diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index e78e576..57293ad 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -216,8 +216,9 @@ RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size); /// @param _direction Direction /// @param _name Name (optional) /// @param _msid MSID (optional) +/// @param _trackID Track ID used in MSID (optional) /// @returns Track id -RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid, rtcDirection direction, const char *_name, const char *_msid); +RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid, rtcDirection direction, const char *_name, const char *_msid, const char *_trackID); /// Set H264PacketizationHandler for track /// @param tr Track id diff --git a/src/candidate.cpp b/src/candidate.cpp index 8fed5c0..eef2c4b 100644 --- a/src/candidate.cpp +++ b/src/candidate.cpp @@ -167,9 +167,12 @@ bool Candidate::resolve(ResolveMode mode) { if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer, MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN, NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - + try { + mPort = uint16_t(std::stoul(servbuffer)); + } catch (...) { + return false; + } mAddress = nodebuffer; - mPort = uint16_t(std::stoul(servbuffer)); mFamily = p->ai_family == AF_INET6 ? Family::Ipv6 : Family::Ipv4; PLOG_VERBOSE << "Resolved candidate: " << mAddress << ' ' << mPort; break; diff --git a/src/capi.cpp b/src/capi.cpp index b961db5..cbff452 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -453,7 +453,7 @@ int rtcDeleteDataChannel(int dc) { #if RTC_ENABLE_MEDIA -void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid) { +void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid, const char *_trackID) { optional name = nullopt; if (_name) { @@ -465,11 +465,16 @@ void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, msid = string(_msid); } - description->addSSRC(ssrc, name, msid); + optional trackID = nullopt; + if (_trackID) { + trackID = string(_trackID); + } + + description->addSSRC(ssrc, name, msid, trackID); } int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid, - rtcDirection _direction, const char *_name, const char *_msid) { + rtcDirection _direction, const char *_name, const char *_msid, const char *_trackID) { return WRAP({ auto peerConnection = getPeerConnection(pc); @@ -534,7 +539,7 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const throw std::invalid_argument("Unexpected codec"); } else { auto description = optDescription.value(); - setSSRC(&description, ssrc, _name, _msid); + setSSRC(&description, ssrc, _name, _msid, _trackID); int tr = emplaceTrack(peerConnection->addTrack(std::move(description))); if (auto ptr = getUserPointer(pc)) { diff --git a/src/configuration.cpp b/src/configuration.cpp index bd918a9..be82575 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -60,32 +60,51 @@ IceServer::IceServer(const string &url) { username = opt[6].value_or(""); password = opt[8].value_or(""); - hostname = opt[10].value(); - service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478"); + hostname = opt[10].value(); while (!hostname.empty() && hostname.front() == '[') hostname.erase(hostname.begin()); while (!hostname.empty() && hostname.back() == ']') hostname.pop_back(); + + string service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478"); + try { + port = uint16_t(std::stoul(service)); + } catch (...) { + throw std::invalid_argument("Invalid ICE server port in URL: " + service); + } } IceServer::IceServer(string hostname_, uint16_t port_) - : IceServer(std::move(hostname_), std::to_string(port_)) {} + : hostname(std::move(hostname_)), port(port_), type(Type::Stun) {} IceServer::IceServer(string hostname_, string service_) - : hostname(std::move(hostname_)), service(std::move(service_)), type(Type::Stun) {} + : hostname(std::move(hostname_)), type(Type::Stun) { + try { + port = uint16_t(std::stoul(service_)); + } catch (...) { + throw std::invalid_argument("Invalid ICE server port: " + service_); + } +} IceServer::IceServer(string hostname_, uint16_t port_, string username_, string password_, RelayType relayType_) - : IceServer(hostname_, std::to_string(port_), std::move(username_), std::move(password_), - relayType_) {} + : hostname(std::move(hostname_)), port(port_), type(Type::Turn), username(std::move(username_)), + password(std::move(password_)), relayType(relayType_) {} IceServer::IceServer(string hostname_, string service_, string username_, string password_, RelayType relayType_) - : hostname(std::move(hostname_)), service(std::move(service_)), type(Type::Turn), - username(std::move(username_)), password(std::move(password_)), relayType(relayType_) {} + : hostname(std::move(hostname_)), type(Type::Turn), username(std::move(username_)), + password(std::move(password_)), relayType(relayType_) { + try { + port = uint16_t(std::stoul(service_)); + } catch (...) { + throw std::invalid_argument("Invalid ICE server port: " + service_); + } +} -ProxyServer::ProxyServer(Type type_, string ip_, uint16_t port_, string username_, string password_) - : type(type_), ip(ip_), port(port_), username(username_), password(password_) {} +ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_, string username_, + string password_) + : type(type_), hostname(hostname_), port(port_), username(username_), password(password_) {} } // namespace rtc diff --git a/src/description.cpp b/src/description.cpp index a2602c2..7e67ae2 100644 --- a/src/description.cpp +++ b/src/description.cpp @@ -59,7 +59,13 @@ inline std::pair parse_pair(string_view attr) { } template T to_integer(string_view s) { - return std::is_signed::value ? T(std::stol(string(s))) : T(std::stoul(string(s))); + const string str(s); + try { + return std::is_signed::value ? T(std::stol(str)) : T(std::stoul(str)); + } + catch(...) { + throw std::invalid_argument("Invalid integer \"" + str + "\" in description"); + } } } // namespace @@ -519,20 +525,20 @@ Description::Entry::removeAttribute(std::vector::iterator it) { } void Description::Media::addSSRC(uint32_t ssrc, std::optional name, - std::optional msid) { + std::optional msid, std::optional trackID) { if (name) mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + *name); else mAttributes.emplace_back("ssrc:" + std::to_string(ssrc)); if (msid) - mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " msid:" + *msid + " " + *msid); + mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " msid:" + *msid + " " + trackID.value_or(*msid)); mSsrcs.emplace_back(ssrc); } void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, std::optional name, - std::optional msid) { + std::optional msid, std::optional trackID) { auto it = mAttributes.begin(); while (it != mAttributes.end()) { if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) { @@ -540,7 +546,7 @@ void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, std::optio } else it++; } - addSSRC(ssrc, std::move(name), std::move(msid)); + addSSRC(ssrc, std::move(name), std::move(msid), std::move(trackID)); } void Description::Media::removeSSRC(uint32_t oldSSRC) { @@ -823,7 +829,7 @@ void Description::Media::parseSdpLine(string_view line) { } else if (key == "rtcp-mux") { // always added } else if (key == "ssrc") { - mSsrcs.emplace_back(std::stoul(string(value))); + mSsrcs.emplace_back(to_integer(value)); } else { Entry::parseSdpLine(line); } @@ -843,7 +849,7 @@ std::vector Description::Media::getSSRCs() { for (auto &val : mAttributes) { PLOG_DEBUG << val; if (val.find("ssrc:") == 0) { - vec.emplace_back(std::stoul(string(val.substr(5, val.find(" "))))); + vec.emplace_back(to_integer(val.substr(5, val.find(" ")))); } } return vec; diff --git a/src/h264rtppacketizer.cpp b/src/h264rtppacketizer.cpp index 779085c..51a141c 100644 --- a/src/h264rtppacketizer.cpp +++ b/src/h264rtppacketizer.cpp @@ -108,7 +108,7 @@ shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { break; } } - index++; + unsigned long long naluStartIndex = index; while (index < message->size()) { diff --git a/src/icetransport.cpp b/src/icetransport.cpp index 9afd53d..0037891 100644 --- a/src/icetransport.cpp +++ b/src/icetransport.cpp @@ -103,11 +103,11 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi // Pick a STUN server for (auto &server : servers) { if (!server.hostname.empty() && server.type == IceServer::Type::Stun) { - if (server.service.empty()) - server.service = "3478"; // STUN UDP port - PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.service << "\""; + if (server.port == 0) + server.port = 3478; // STUN UDP port + PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port << "\""; jconfig.stun_server_host = server.hostname.c_str(); - jconfig.stun_server_port = uint16_t(std::stoul(server.service)); + jconfig.stun_server_port = server.port; break; } } @@ -119,13 +119,13 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi int k = 0; for (auto &server : servers) { if (!server.hostname.empty() && server.type == IceServer::Type::Turn) { - if (server.service.empty()) - server.service = "3478"; // TURN UDP port - PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.service << "\""; + if (server.port == 0) + server.port = 3478; // TURN UDP port + PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\""; turn_servers[k].host = server.hostname.c_str(); turn_servers[k].username = server.username.c_str(); turn_servers[k].password = server.password.c_str(); - turn_servers[k].port = uint16_t(std::stoul(server.service)); + turn_servers[k].port = server.port; if (++k >= MAX_TURN_SERVERS_COUNT) break; } @@ -402,7 +402,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi if (config.proxyServer.has_value()) { ProxyServer proxyServer = config.proxyServer.value(); g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-type", proxyServer.type, nullptr); - g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.ip.c_str(), nullptr); + g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.hostname.c_str(), nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-port", proxyServer.port, nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-username", proxyServer.username.c_str(), nullptr); @@ -422,8 +422,8 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi continue; if (server.type != IceServer::Type::Stun) continue; - if (server.service.empty()) - server.service = "3478"; // STUN UDP port + if (server.port == 0) + server.port = 3478; // STUN UDP port struct addrinfo hints = {}; hints.ai_family = AF_INET; // IPv4 @@ -431,9 +431,10 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_ADDRCONFIG; struct addrinfo *result = nullptr; - if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0) { + if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints, + &result) != 0) { PLOG_WARNING << "Unable to resolve STUN server address: " << server.hostname << ':' - << server.service; + << server.port; continue; } @@ -444,7 +445,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICNODE_LEN, NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.service + PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port << "\""; g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port", @@ -466,8 +467,8 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi continue; if (server.type != IceServer::Type::Turn) continue; - if (server.service.empty()) - server.service = server.relayType == IceServer::RelayType::TurnTls ? "5349" : "3478"; + if (server.port == 0) + server.port = server.relayType == IceServer::RelayType::TurnTls ? 5349 : 3478; struct addrinfo hints = {}; hints.ai_family = AF_UNSPEC; @@ -477,9 +478,10 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP; hints.ai_flags = AI_ADDRCONFIG; struct addrinfo *result = nullptr; - if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0) { + if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints, + &result) != 0) { PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':' - << server.service; + << server.port; continue; } @@ -490,7 +492,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICNODE_LEN, NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.service + PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\""; NiceRelayType niceRelayType; switch (server.relayType) { diff --git a/src/processor.cpp b/src/processor.cpp index 5e83e47..d5f98c4 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -25,18 +25,39 @@ Processor::Processor(size_t limit) : mTasks(limit) {} Processor::~Processor() { join(); } void Processor::join() { - std::unique_lock lock(mMutex); - mCondition.wait(lock, [this]() { return !mPending && mTasks.empty(); }); + // We need to detect situations where the thread pool does not execute a pending task at exit + std::optional counter; + while (true) { + std::shared_future pending; + { + std::unique_lock lock(mMutex); + if (!mPending // no pending task + || (counter && *counter == mCounter)) { // or no scheduled task after the last one + + // Processing is stopped, clear everything and return + mPending.reset(); + while (!mTasks.empty()) + mTasks.pop(); + + return; + } + + pending = *mPending; + counter = mCounter; + } + + // Wait for the pending task + pending.wait(); + } } void Processor::schedule() { std::unique_lock lock(mMutex); if (auto next = mTasks.tryPop()) { - ThreadPool::Instance().enqueue(std::move(*next)); + mPending = ThreadPool::Instance().enqueue(std::move(*next)).share(); + ++mCounter; } else { - // No more tasks - mPending = false; - mCondition.notify_all(); + mPending.reset(); // No more tasks } } diff --git a/src/processor.hpp b/src/processor.hpp index a63259b..47a82bc 100644 --- a/src/processor.hpp +++ b/src/processor.hpp @@ -54,10 +54,10 @@ protected: const init_token mInitToken = Init::Token(); Queue> mTasks; - bool mPending = false; // true iff a task is pending in the thread pool + std::optional> mPending; // future of the pending task + unsigned int mCounter = 0; // Number of scheduled tasks mutable std::mutex mMutex; - std::condition_variable mCondition; }; template void Processor::enqueue(F &&f, Args &&...args) { @@ -65,12 +65,12 @@ template void Processor::enqueue(F &&f, Args &&...args) auto bound = std::bind(std::forward(f), std::forward(args)...); auto task = [this, bound = std::move(bound)]() mutable { scope_guard guard(std::bind(&Processor::schedule, this)); // chain the next task - return bound(); + bound(); }; if (!mPending) { - ThreadPool::Instance().enqueue(std::move(task)); - mPending = true; + mPending = ThreadPool::Instance().enqueue(std::move(task)).share(); + ++mCounter; } else { mTasks.push(std::move(task)); } diff --git a/src/sctptransport.cpp b/src/sctptransport.cpp index 994eb20..2340ff4 100644 --- a/src/sctptransport.cpp +++ b/src/sctptransport.cpp @@ -588,7 +588,6 @@ int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, uint8_t std::unique_lock lock(mWriteMutex); PLOG_VERBOSE << "Handle write, len=" << len; - auto message = make_message(data, data + len); if (!outgoing(make_message(data, data + len))) return -1; diff --git a/src/threadpool.cpp b/src/threadpool.cpp index 261195e..9a7be69 100644 --- a/src/threadpool.cpp +++ b/src/threadpool.cpp @@ -96,6 +96,10 @@ std::function ThreadPool::dequeue() { mCondition.wait(lock); } } + + while (!mTasks.empty()) + mTasks.pop(); + return nullptr; } diff --git a/src/threadpool.hpp b/src/threadpool.hpp index bb134a7..8f56894 100644 --- a/src/threadpool.hpp +++ b/src/threadpool.hpp @@ -100,8 +100,16 @@ auto ThreadPool::schedule(clock::duration delay, F &&f, Args &&...args) template auto ThreadPool::schedule(clock::time_point time, F &&f, Args &&...args) -> invoke_future_t { - std::unique_lock lock(mMutex); using R = std::invoke_result_t, std::decay_t...>; + std::unique_lock lock(mMutex); + if (mJoining) { + std::promise promise; + std::future result = promise.get_future(); + promise.set_exception(std::make_exception_ptr( + std::runtime_error("Scheduled a task while joining the thread pool"))); + return result; + } + auto bound = std::bind(std::forward(f), std::forward(args)...); auto task = std::make_shared>([bound = std::move(bound)]() mutable { try { diff --git a/test/uwp/benchmark/Logo.png b/test/uwp/benchmark/Logo.png new file mode 100644 index 0000000..65f91ac Binary files /dev/null and b/test/uwp/benchmark/Logo.png differ diff --git a/test/uwp/benchmark/SmallLogo.png b/test/uwp/benchmark/SmallLogo.png new file mode 100644 index 0000000..460c022 Binary files /dev/null and b/test/uwp/benchmark/SmallLogo.png differ diff --git a/test/uwp/benchmark/SmallLogo44x44.png b/test/uwp/benchmark/SmallLogo44x44.png new file mode 100644 index 0000000..c237458 Binary files /dev/null and b/test/uwp/benchmark/SmallLogo44x44.png differ diff --git a/test/uwp/benchmark/SplashScreen.png b/test/uwp/benchmark/SplashScreen.png new file mode 100644 index 0000000..8342565 Binary files /dev/null and b/test/uwp/benchmark/SplashScreen.png differ diff --git a/test/uwp/benchmark/StoreLogo.png b/test/uwp/benchmark/StoreLogo.png new file mode 100644 index 0000000..508c8a8 Binary files /dev/null and b/test/uwp/benchmark/StoreLogo.png differ diff --git a/test/uwp/benchmark/Windows_TemporaryKey.pfx b/test/uwp/benchmark/Windows_TemporaryKey.pfx new file mode 100644 index 0000000..1cad999 Binary files /dev/null and b/test/uwp/benchmark/Windows_TemporaryKey.pfx differ diff --git a/test/uwp/benchmark/package.appxManifest b/test/uwp/benchmark/package.appxManifest new file mode 100644 index 0000000..8cd7981 --- /dev/null +++ b/test/uwp/benchmark/package.appxManifest @@ -0,0 +1,42 @@ + + + + + + + datachannel-benchmark + CMake + StoreLogo.png + + + + + + + + + + + + + + + diff --git a/test/uwp/tests/Logo.png b/test/uwp/tests/Logo.png new file mode 100644 index 0000000..65f91ac Binary files /dev/null and b/test/uwp/tests/Logo.png differ diff --git a/test/uwp/tests/SmallLogo.png b/test/uwp/tests/SmallLogo.png new file mode 100644 index 0000000..460c022 Binary files /dev/null and b/test/uwp/tests/SmallLogo.png differ diff --git a/test/uwp/tests/SmallLogo44x44.png b/test/uwp/tests/SmallLogo44x44.png new file mode 100644 index 0000000..c237458 Binary files /dev/null and b/test/uwp/tests/SmallLogo44x44.png differ diff --git a/test/uwp/tests/SplashScreen.png b/test/uwp/tests/SplashScreen.png new file mode 100644 index 0000000..8342565 Binary files /dev/null and b/test/uwp/tests/SplashScreen.png differ diff --git a/test/uwp/tests/StoreLogo.png b/test/uwp/tests/StoreLogo.png new file mode 100644 index 0000000..508c8a8 Binary files /dev/null and b/test/uwp/tests/StoreLogo.png differ diff --git a/test/uwp/tests/Windows_TemporaryKey.pfx b/test/uwp/tests/Windows_TemporaryKey.pfx new file mode 100644 index 0000000..1cad999 Binary files /dev/null and b/test/uwp/tests/Windows_TemporaryKey.pfx differ diff --git a/test/uwp/tests/package.appxManifest b/test/uwp/tests/package.appxManifest new file mode 100644 index 0000000..1da7e86 --- /dev/null +++ b/test/uwp/tests/package.appxManifest @@ -0,0 +1,42 @@ + + + + + + + datachannel-tests + CMake + StoreLogo.png + + + + + + + + + + + + + + +