Compare commits

...

74 Commits

Author SHA1 Message Date
41cba8a35a Bumped version to 0.13.3 2021-05-29 19:23:02 +02:00
6c683b326d Added ostream operator for LogLevel 2021-05-29 19:22:28 +02:00
8184d1d60e Updated libjuice to v0.7.4 2021-05-28 23:07:57 +02:00
8da8c8a6d0 Bumped version to v0.13.2 2021-05-28 21:56:21 +02:00
6a4a22a87c Fixed reference when iterating on prefixes array 2021-05-28 21:54:03 +02:00
724fefbfdb Merge pull request #428 from paullouisageneau/fix-sctp-global-instances-set
Fix possible static de-initialization order issue in SctpTransport
2021-05-28 21:50:39 +02:00
83cc26d4a5 Fixed possible static deinit order issue with SctpTransport instances set 2021-05-28 21:49:55 +02:00
fd97f98f23 Bumped version to 0.13.1 2021-05-17 19:06:45 +02:00
76d9ce5ba3 Updated libjuice to v0.7.3 2021-05-17 09:58:27 +02:00
f795e3293f Merge pull request #423 from paullouisageneau/remove-usrsctp-data-race-mitigation
Remove usrsctp data race mitigation
2021-05-16 19:09:56 +02:00
34aad791c6 Removed usrsctp data race mitigation 2021-05-16 18:31:54 +02:00
30703741e5 Merge pull request #420 from wasphin/feature/fix-export-name
Fix cmake export file name
2021-05-14 21:48:59 +02:00
wxf
124c073821 Fix cmake export file name 2021-05-14 11:52:44 +08:00
9457492169 Bumped version to 0.13.0 2021-05-07 21:30:04 +02:00
384c84e8aa Merge branch 'v0.12' 2021-05-07 21:26:17 +02:00
e4ab5273fc Bumped version to 0.12.3 2021-05-07 21:24:17 +02:00
b315869989 Bumped libjuice to v0.7.2 2021-04-30 22:30:34 +02:00
aea6708d27 Merge pull request #416 from paullouisageneau/cleanup-api
Refactor C media API
2021-04-29 17:12:37 +02:00
2166386d42 Fixed comments 2021-04-29 16:07:04 +02:00
f88394ab75 Merge pull request #418 from paullouisageneau/cleanup-has-description
Remove declarations of hasLocalDescription() and hasRemoteDescription()
2021-04-29 16:04:28 +02:00
ba7e0e2a35 Removed declarations of hasLocalDescription() and hasRemoteDescription() 2021-04-29 15:24:08 +02:00
fba965b46c Fixed compilation without media 2021-04-28 21:36:36 +02:00
eff0faf6e1 Refactored C media API 2021-04-27 22:58:46 +02:00
cd68d1dba7 Use make_shared where possible 2021-04-26 22:34:06 +02:00
ce9fa374d0 Merge pull request #414 from paullouisageneau/sctp-max-burst
Add SCTP max burst setting
2021-04-26 21:31:47 +02:00
2bf03205cf Added entry for sfu-media 2021-04-24 15:01:04 +02:00
07a5591cda Added comments for SCTP settings 2021-04-20 19:28:54 +02:00
282ca48b12 Added max burst setting for SCTP 2021-04-20 19:28:54 +02:00
bf0b3ce1b9 Resolve use of deprecated ::result_type typedef.
Also adds #include <utility> since this file names std::move.

```
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(std::weak_ptr<_Ty>)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(rtc::Candidate)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<bool (__cdecl rtc::impl::PeerConnection::* )(const std::string &) const>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(rtc::message_ptr)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(uint16_t,size_t)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
```
2021-04-20 09:20:56 +02:00
48a275f830 Merge pull request #413 from BillyONeal/warning_fix
Resolve use of deprecated ::result_type typedef.
2021-04-20 09:11:56 +02:00
a15b2ad468 Resolve use of deprecated ::result_type typedef.
Also adds #include <utility> since this file names std::move.

```
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(std::weak_ptr<_Ty>)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(rtc::Candidate)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<bool (__cdecl rtc::impl::PeerConnection::* )(const std::string &) const>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(rtc::message_ptr)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
         D:\buildtrees\libdatachannel\src\v0.12.0-2d418b9dcd.clean\include\rtc\utils.hpp(35,23): error C4996: 'std::_Weak_result_type<std::_Is_memfunptr<void (__cdecl rtc::impl::PeerConnection::* )(uint16_t,size_t)>,void>::result_type': warning STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. You can define _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. [D:\buildtrees\libdatachannel\x64-uwp-dbg\datachannel.vcxproj]
```
2021-04-19 14:41:53 -07:00
afd4639d2d Merge pull request #410 from paullouisageneau/cmake-improvements
CMake improvements
2021-04-19 18:50:18 +02:00
653ec35ba8 Merge pull request #411 from paullouisageneau/dependabot/npm_and_yarn/examples/signaling-server-nodejs/websocket-1.0.34
Bump websocket from 1.0.33 to 1.0.34 in /examples/signaling-server-nodejs
2021-04-19 09:33:32 +02:00
2d344f1186 Bump websocket in /examples/signaling-server-nodejs
Bumps [websocket](https://github.com/theturtle32/WebSocket-Node) from 1.0.33 to 1.0.34.
- [Release notes](https://github.com/theturtle32/WebSocket-Node/releases)
- [Changelog](https://github.com/theturtle32/WebSocket-Node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/theturtle32/WebSocket-Node/compare/v1.0.33...v1.0.34)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-19 07:13:42 +00:00
13f3624aee CMake improvements 2021-04-18 09:53:59 +02:00
ebe64ed8ef Merge pull request #408 from paullouisageneau/open-cb-recv-dc
Call DataChannel::onOpen() callback on receiving side
2021-04-15 22:59:03 +02:00
ae429410fe Introduced synchronized_stored_callback to support callbacks set after they are triggered 2021-04-15 22:21:24 +02:00
bbbc8ca4e6 Introduced onOpen() callback in client example 2021-04-15 09:38:00 +02:00
5346d31cc1 Introduced onOpen() callback on receiving side in tests 2021-04-15 09:21:56 +02:00
d86de619dc Enforce proper callback order between open and message 2021-04-15 09:21:56 +02:00
d62166e1a7 Trigger open callback after data channel or track callback 2021-04-15 09:21:56 +02:00
b353fbe44d Refactored flushing of pending DataChannels and Tracks 2021-04-15 09:21:56 +02:00
079926443c Merge branch 'v0.12' 2021-04-15 09:21:35 +02:00
2ed6845201 Merge pull request #404 from paullouisageneau/plog-private
Make plog a private dependency
2021-04-14 21:42:17 +02:00
655175d21e Bumped version to 0.12.2 2021-04-14 12:24:12 +02:00
c85943e916 support finding openssl form homebrew on M1 Macs
homebrew changed its default installation paths for M1 Macs
2021-04-14 12:22:26 +02:00
6aee0ff12c Merge pull request #407 from arvidn/homebrew-m1-openssl
support finding openssl from homebrew on M1 Macs
2021-04-14 12:21:19 +02:00
6cea78c618 support finding openssl form homebrew on M1 Macs
homebrew changed its default installation paths for M1 Macs
2021-04-14 07:54:01 +02:00
c929be592b Fixed struct timeval undeclared on Windows 2021-04-13 23:03:16 +02:00
0c882d074e Marked packetizers and RTCP handlers final 2021-04-13 23:03:16 +02:00
4ca78db146 Reorganized stuff to make plog private 2021-04-13 23:03:16 +02:00
2fd3da482a Merge pull request #406 from paullouisageneau/v0.12
Make impl::DataChannel destructor virtual
2021-04-13 23:02:06 +02:00
9bc9eea5b4 Merge pull request #405 from paullouisageneau/fix-license-headers
Fixed example license headers in library
2021-04-13 22:59:22 +02:00
d7261dd0ac Fixed example license headers in library 2021-04-13 22:57:48 +02:00
1cc7910bf1 Made impl::DataChannel destructor virtual 2021-04-13 22:29:25 +02:00
436d77eab7 Merge pull request #400 from paullouisageneau/sctp-settings
Add SCTP settings API
2021-04-13 21:51:06 +02:00
93b598a78c Merge pull request #402 from murat-dogan/simple-fix
Simple fix
2021-04-13 21:49:51 +02:00
e4019ebec8 define macMessegeSize 2021-04-13 15:00:25 +03:00
89c0a7918a delete unneeded module 2021-04-13 14:41:51 +03:00
6b5d888db3 Fixed recv instead of send for buffer size 2021-04-13 09:45:42 +02:00
0fddf50245 Reorganized includes to hide Init implementation 2021-04-12 22:12:10 +02:00
251bfc7def Added SCTP settings API and enhanced integer conversions in SctpTransport 2021-04-12 19:11:53 +02:00
dd4949e78e Merge pull request #398 from murat-dogan/master
Add Multiple Data Channel Option
2021-04-11 21:07:41 +02:00
0d0e3ae0ff use at method of unordered_map 2021-04-11 16:51:44 +03:00
b3a980f079 Change unordered_map write logic 2021-04-11 13:22:48 +03:00
ab946bb711 Multiple Data Channel Output Example 2021-04-10 19:58:48 +03:00
120e57cc5c fix app outputs 2021-04-10 19:55:59 +03:00
f1080bfd0f implement dataChannelCount option 2021-04-10 19:48:26 +03:00
8190188a05 add dataChannelCount option 2021-04-10 19:48:10 +03:00
a48f080605 Merge branch 'v0.12' 2021-04-10 16:25:46 +02:00
62b435a4aa Fixed compilation warnings 2021-04-10 16:22:05 +02:00
9da756bd12 Updated Jamfile 2021-04-10 10:54:10 +02:00
1acfcaa830 Added missing include in Jamfile 2021-04-10 09:38:01 +02:00
f5b584f536 Handle empty RTCIceCandidate.candidate as "end of candidates" indicator 2021-04-08 15:10:26 +02:00
85 changed files with 2540 additions and 1754 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
project(libdatachannel project(libdatachannel
VERSION 0.12.1 VERSION 0.13.3
LANGUAGES CXX) LANGUAGES CXX)
set(PROJECT_DESCRIPTION "WebRTC Data Channels Library") set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
@ -43,8 +43,7 @@ set(LIBDATACHANNEL_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/init.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/log.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpreceivingsession.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpreceivingsession.cpp
@ -62,6 +61,7 @@ set(LIBDATACHANNEL_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerelement.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerelement.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerrootelement.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerrootelement.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp
) )
@ -75,8 +75,7 @@ set(LIBDATACHANNEL_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandler.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandler.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/init.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/global.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/log.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/reliability.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/reliability.hpp
@ -107,6 +106,7 @@ set(LIBDATACHANNEL_IMPL_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/sctptransport.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/sctptransport.cpp
@ -129,6 +129,8 @@ set(LIBDATACHANNEL_IMPL_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/internals.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/queue.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/queue.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.hpp
@ -213,17 +215,17 @@ set_target_properties(datachannel-static PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
CXX_STANDARD 17) CXX_STANDARD 17)
target_include_directories(datachannel PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(datachannel PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc) target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(datachannel PUBLIC Threads::Threads plog::plog) target_link_libraries(datachannel PUBLIC Threads::Threads)
target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp) target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp plog::plog)
target_include_directories(datachannel-static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(datachannel-static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc) target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(datachannel-static PUBLIC Threads::Threads plog::plog) target_link_libraries(datachannel-static PUBLIC Threads::Threads)
target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp) target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp plog::plog)
if(WIN32) if(WIN32)
target_link_libraries(datachannel PUBLIC ws2_32) # winsock2 target_link_libraries(datachannel PUBLIC ws2_32) # winsock2
@ -310,9 +312,6 @@ endif()
add_library(LibDataChannel::LibDataChannel ALIAS datachannel) add_library(LibDataChannel::LibDataChannel ALIAS datachannel)
add_library(LibDataChannel::LibDataChannelStatic ALIAS datachannel-static) add_library(LibDataChannel::LibDataChannelStatic ALIAS datachannel-static)
install(TARGETS datachannel LIBRARY DESTINATION lib)
install(FILES ${LIBDATACHANNEL_HEADERS} DESTINATION include/rtc)
if(NOT MSVC) if(NOT MSVC)
target_compile_options(datachannel PRIVATE -Wall -Wextra) target_compile_options(datachannel PRIVATE -Wall -Wextra)
target_compile_options(datachannel-static PRIVATE -Wall -Wextra) target_compile_options(datachannel-static PRIVATE -Wall -Wextra)
@ -328,6 +327,22 @@ if(WARNINGS_AS_ERRORS)
endif() endif()
endif() endif()
install(TARGETS datachannel EXPORT libdatachannel-config
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install(FILES ${LIBDATACHANNEL_HEADERS}
DESTINATION include/rtc
)
install(
EXPORT libdatachannel-config
NAMESPACE LibDatachannel::
DESTINATION share/cmake/libdatachannel
)
# Tests # Tests
if(NOT NO_TESTS) if(NOT NO_TESTS)
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")

View File

@ -12,9 +12,12 @@ feature.compose <gnutls>on
lib libdatachannel lib libdatachannel
: # sources : # sources
[ glob ./src/*.cpp ] [ glob ./src/*.cpp ]
[ glob ./src/impl/*.cpp ]
: # requirements : # requirements
<cxxstd>17 <cxxstd>17
<include>./include
<include>./include/rtc <include>./include/rtc
<include>./src
<define>RTC_ENABLE_MEDIA=0 <define>RTC_ENABLE_MEDIA=0
<define>RTC_ENABLE_WEBSOCKET=0 <define>RTC_ENABLE_WEBSOCKET=0
<define>USE_NICE=0 <define>USE_NICE=0
@ -143,7 +146,7 @@ rule make_libjuice_openssl ( targets * : sources * : properties * )
{ {
# on macOS, default to pick up openssl from the homebrew installation # on macOS, default to pick up openssl from the homebrew installation
# brew install openssl # brew install openssl
OPENSSL_INCLUDE = /usr/local/opt/openssl/include ; OPENSSL_INCLUDE = /opt/homebrew/opt/openssl /usr/local/opt/openssl/include ;
} }
if $(OPENSSL_INCLUDE) != "" if $(OPENSSL_INCLUDE) != ""
@ -191,7 +194,7 @@ rule openssl-lib-path ( properties * )
{ {
# on macOS, default to pick up openssl from the homebrew installation # on macOS, default to pick up openssl from the homebrew installation
# brew install openssl # brew install openssl
OPENSSL_LIB = /usr/local/opt/openssl/lib ; OPENSSL_LIB = /opt/homebrew/opt/openssl/lib /usr/local/opt/openssl/lib ;
} }
else if <target-os>windows in $(properties) && $(OPENSSL_LIB) = "" else if <target-os>windows in $(properties) && $(OPENSSL_LIB) = ""
{ {
@ -217,7 +220,7 @@ rule openssl-include-path ( properties * )
{ {
# on macOS, default to pick up openssl from the homebrew installation # on macOS, default to pick up openssl from the homebrew installation
# brew install openssl # brew install openssl
OPENSSL_INCLUDE = /usr/local/opt/openssl/include ; OPENSSL_INCLUDE = /opt/homebrew/opt/openssl/include /usr/local/opt/openssl/include ;
} }
else if <target-os>windows in $(properties) && $(OPENSSL_INCLUDE) = "" else if <target-os>windows in $(properties) && $(OPENSSL_INCLUDE) = ""
{ {

2
deps/libjuice vendored

View File

@ -10,6 +10,7 @@ This directory contains different WebRTC clients and compatible WebSocket + JSON
- [signaling-server-rust](signaling-server-rust) contains a similar signaling server in Rust (see [lerouxrgd/datachannel-rs](https://github.com/lerouxrgd/datachannel-rs) for Rust wrappers) - [signaling-server-rust](signaling-server-rust) contains a similar signaling server in Rust (see [lerouxrgd/datachannel-rs](https://github.com/lerouxrgd/datachannel-rs) for Rust wrappers)
- [media](media) is a copy/paste demo to send the webcam from your browser into gstreamer. - [media](media) is a copy/paste demo to send the webcam from your browser into gstreamer.
- [sfu-media](sfu-media) is a copy/paste SFU demo to relay the webcam between browsers.
- [streamer](streamer) streams h264 and opus samples to web browsers (signaling-server-python is required). - [streamer](streamer) streams h264 and opus samples to web browsers (signaling-server-python is required).
Additionally, it contains two debugging tools for libdatachannel with copy-pasting as signaling: Additionally, it contains two debugging tools for libdatachannel with copy-pasting as signaling:

View File

@ -1,8 +1,9 @@
# libdatachannel - client-benchmark # libdatachannel - client-benchmark
This directory contains a native client to open Data Channels with WebSocket signaling using libdatachannel and benchmark functionalities. It offers two functionalities; This directory contains a native client to open Data Channels with WebSocket signaling using libdatachannel and benchmark functionalities. It offers three functionalities;
- Benchmark: Bi-directional data transfer benchmark (Also supports One-Way testing) - Benchmark: Bi-directional data transfer benchmark (Also supports One-Way testing)
- Constant Throughput Set: Send desired amount of data per second - Constant Throughput Set: Send desired amount of data per second
- Multiple Data Channel: Create desried count of data channel
## Start Signaling Server ## Start Signaling Server
- Start one of the signaling server from the examples folder. For example start `signaling-server-nodejs` like; - Start one of the signaling server from the examples folder. For example start `signaling-server-nodejs` like;
@ -12,7 +13,7 @@ This directory contains a native client to open Data Channels with WebSocket sig
## Start `client-benchmark` Applications ## Start `client-benchmark` Applications
Start 2 applications by using example calls below. Than copy one of the client's ID and paste to the other peer's screen to start offering process. Start 2 applications by using example calls below. Then copy one of the client's ID and paste to the other peer's screen to start offering process.
## Usage Examples ## Usage Examples
@ -23,63 +24,90 @@ Start 2 applications by using example calls below. Than copy one of the client's
Example Output (Offering Peer's Output); Example Output (Offering Peer's Output);
```bash ```bash
Stun server is stun:stun.l.google.com:19302 Stun server is stun:stun.l.google.com:19302
The local ID is: EQmF The local ID is: H1E3
Url is ws://localhost:8000/EQmF Url is ws://localhost:8000/H1E3
Waiting for signaling to be connected... Waiting for signaling to be connected...
2021-03-25 14:21:58.045 INFO [21386] [rtc::impl::TcpTransport::connect@159] Connected to localhost:8000 2021-04-10 19:51:31.319 INFO [16449] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-03-25 14:21:58.045 INFO [21386] [rtc::impl::TcpTransport::runLoop@327] TCP connected 2021-04-10 19:51:31.319 INFO [16449] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-03-25 14:21:58.046 INFO [21386] [rtc::impl::WsTransport::incoming@118] WebSocket open 2021-04-10 19:51:31.321 INFO [16449] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready WebSocket connected, signaling ready
Enter a remote ID to send an offer: Enter a remote ID to send an offer:
0tDf n790
Offering to 0tDf Offering to n790
Creating DataChannel with label "benchmark" Creating DataChannel with label "DC-1"
2021-03-25 14:22:07.972 INFO [21379] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302" 2021-04-10 19:51:32.464 INFO [16442] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-03-25 14:22:07.973 INFO [21379] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to new 2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-03-25 14:22:07.973 INFO [21379] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress 2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
Gathering State: in-progress Gathering State: in-progress
2021-03-25 14:22:07.974 INFO [21379] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering 2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
2021-03-25 14:22:07.974 WARN [21379] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:239: Local description already has the maximum number of host candidates
Benchmark will run for 300 seconds Benchmark will run for 300 seconds
2021-03-25 14:22:07.976 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting 2021-04-10 19:51:32.466 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
2021-03-25 14:22:07.976 INFO [21396] [rtc::impl::PeerConnection::changeState@964] Changed state to connecting 2021-04-10 19:51:32.466 INFO [16450] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
State: connecting State: connecting
2021-03-25 14:22:08.055 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302 2021-04-10 19:51:32.489 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
2021-03-25 14:22:08.055 INFO [21386] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to connecting 2021-04-10 19:51:32.489 INFO [16449] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-03-25 14:22:08.105 WARN [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101 2021-04-10 19:51:32.490 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-03-25 14:22:08.105 WARN [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101 2021-04-10 19:51:32.491 INFO [16453] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-03-25 14:22:08.105 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed 2021-04-10 19:51:32.497 INFO [16443] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful 2021-04-10 19:51:32.497 INFO [16443] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete
Gathering State: complete
2021-03-25 14:22:08.155 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-03-25 14:22:08.206 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
#1 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
2021-03-25 14:22:09.059 INFO [21399] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-03-25 14:22:09.069 INFO [21382] [rtc::impl::SctpTransport::processNotification@708] SCTP connected
2021-03-25 14:22:09.069 INFO [21382] [rtc::impl::PeerConnection::changeState@964] Changed state to connected
State: connected State: connected
DataChannel from 0tDf open DataChannel from n790 open
#2 Received: 41488 KB/s Sent: 42465 KB/s BufferSize: 65535 2021-04-10 19:51:32.542 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
#3 Received: 43925 KB/s Sent: 43729 KB/s BufferSize: 65535 2021-04-10 19:51:32.589 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
#4 Received: 42491 KB/s Sent: 42361 KB/s BufferSize: 65535 #1
#5 Received: 45878 KB/s Sent: 45682 KB/s BufferSize: 65535 DC-1 Received: 40789 KB/s Sent: 41180 KB/s BufferSize: 65535
Stats# Received Total: 174 MB Sent Total: 175 MB RTT: 17 ms TOTL Received: 40789 KB/s Sent: 41180 KB/s
2021-04-10 19:51:34.039 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
2021-04-10 19:51:34.039 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
2021-04-10 19:51:34.039 INFO [16450] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
Gathering State: complete
#2
DC-1 Received: 41709 KB/s Sent: 41774 KB/s BufferSize: 65535
TOTL Received: 41709 KB/s Sent: 41774 KB/s
#3
DC-1 Received: 42165 KB/s Sent: 42360 KB/s BufferSize: 65535
TOTL Received: 42165 KB/s Sent: 42360 KB/s
#4
DC-1 Received: 42880 KB/s Sent: 42750 KB/s BufferSize: 65535
TOTL Received: 42880 KB/s Sent: 42750 KB/s
#5
DC-1 Received: 41771 KB/s Sent: 42097 KB/s BufferSize: 65535
TOTL Received: 41771 KB/s Sent: 42097 KB/s
Stats# Received Total: 210 MB Sent Total: 211 MB RTT: 20 ms
#6 Received: 43665 KB/s Sent: 43599 KB/s BufferSize: 65535 #6
#7 Received: 45749 KB/s Sent: 45488 KB/s BufferSize: 65535 DC-1 Received: 46235 KB/s Sent: 30433 KB/s BufferSize: 65535
#8 Received: 44055 KB/s Sent: 44055 KB/s BufferSize: 65535 TOTL Received: 46235 KB/s Sent: 30433 KB/s
#9 Received: 21572 KB/s Sent: 58199 KB/s BufferSize: 65535 #7
#10 Received: 22940 KB/s Sent: 55005 KB/s BufferSize: 65535 DC-1 Received: 47116 KB/s Sent: 28413 KB/s BufferSize: 65535
Stats# Received Total: 353 MB Sent Total: 422 MB RTT: 15 ms TOTL Received: 47116 KB/s Sent: 28413 KB/s
#8
DC-1 Received: 46923 KB/s Sent: 32520 KB/s BufferSize: 65535
TOTL Received: 46923 KB/s Sent: 32520 KB/s
#9
DC-1 Received: 44513 KB/s Sent: 34020 KB/s BufferSize: 65535
TOTL Received: 44513 KB/s Sent: 34020 KB/s
#10
DC-1 Received: 41966 KB/s Sent: 36166 KB/s BufferSize: 65535
TOTL Received: 41966 KB/s Sent: 36166 KB/s
Stats# Received Total: 438 MB Sent Total: 373 MB RTT: 19 ms
#11 Received: 27501 KB/s Sent: 53112 KB/s BufferSize: 65535 #11
#12 Received: 29914 KB/s Sent: 48162 KB/s BufferSize: 65535 DC-1 Received: 42617 KB/s Sent: 39619 KB/s BufferSize: 65535
#13 Received: 31869 KB/s Sent: 45946 KB/s BufferSize: 65535 TOTL Received: 42617 KB/s Sent: 39619 KB/s
#14 Received: 22484 KB/s Sent: 53636 KB/s BufferSize: 65535 #12
#15 Received: 16294 KB/s Sent: 56833 KB/s BufferSize: 65535 DC-1 Received: 43792 KB/s Sent: 43338 KB/s BufferSize: 65535
Stats# Received Total: 482 MB Sent Total: 682 MB RTT: 13 ms TOTL Received: 43792 KB/s Sent: 43338 KB/s
#13
DC-1 Received: 41715 KB/s Sent: 41585 KB/s BufferSize: 65535
TOTL Received: 41715 KB/s Sent: 41585 KB/s
#14
DC-1 Received: 39860 KB/s Sent: 33822 KB/s BufferSize: 65535
TOTL Received: 39860 KB/s Sent: 33822 KB/s
#15
DC-1 Received: 47576 KB/s Sent: 25352 KB/s BufferSize: 65535
TOTL Received: 47576 KB/s Sent: 25352 KB/s
Stats# Received Total: 655 MB Sent Total: 558 MB RTT: 13 ms
``` ```
### Benchmark for 300 seconds (Only Send, One Way) ### Benchmark for 300 seconds (Only Send, One Way)
@ -92,64 +120,92 @@ Start second peer as;
Example Output (Offering Peer's Output); Example Output (Offering Peer's Output);
```bash ```bash
Not Sending data. (One way benchmark).
Stun server is stun:stun.l.google.com:19302 Stun server is stun:stun.l.google.com:19302
The local ID is: XLLn The local ID is: 7EaP
Url is ws://localhost:8000/XLLn Url is ws://localhost:8000/7EaP
Waiting for signaling to be connected... Waiting for signaling to be connected...
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::TcpTransport::connect@159] Connected to localhost:8000 2021-04-10 19:54:36.857 INFO [16632] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::TcpTransport::runLoop@327] TCP connected 2021-04-10 19:54:36.857 INFO [16632] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::WsTransport::incoming@118] WebSocket open 2021-04-10 19:54:36.858 INFO [16632] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready WebSocket connected, signaling ready
Enter a remote ID to send an offer: Enter a remote ID to send an offer:
Okt4 UDL4
Offering to Okt4 Offering to UDL4
Creating DataChannel with label "benchmark" Creating DataChannel with label "DC-1"
2021-03-25 14:34:37.948 INFO [22325] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302" 2021-04-10 19:54:53.381 INFO [16625] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-03-25 14:34:37.949 INFO [22325] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to new 2021-04-10 19:54:53.382 INFO [16625] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-03-25 14:34:37.949 INFO [22325] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress 2021-04-10 19:54:53.382 INFO [16625] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
Gathering State: in-progress Gathering State: in-progress
2021-03-25 14:34:37.950 INFO [22325] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering 2021-04-10 19:54:53.383 INFO [16625] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
2021-03-25 14:34:37.951 WARN [22325] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:239: Local description already has the maximum number of host candidates
Benchmark will run for 300 seconds Benchmark will run for 300 seconds
2021-03-25 14:34:37.952 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting 2021-04-10 19:54:53.384 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
2021-03-25 14:34:37.952 INFO [22334] [rtc::impl::PeerConnection::changeState@964] Changed state to connecting 2021-04-10 19:54:53.384 INFO [16646] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
State: connecting State: connecting
2021-03-25 14:34:37.969 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302 2021-04-10 19:54:53.475 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
2021-03-25 14:34:37.969 INFO [22332] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to connecting 2021-04-10 19:54:53.475 INFO [16632] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-03-25 14:34:37.970 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected 2021-04-10 19:54:53.527 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
2021-03-25 14:34:37.971 INFO [22337] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished 2021-04-10 19:54:53.575 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-03-25 14:34:37.977 INFO [22327] [rtc::impl::SctpTransport::processNotification@708] SCTP connected 2021-04-10 19:54:53.625 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
2021-03-25 14:34:37.977 INFO [22327] [rtc::impl::PeerConnection::changeState@964] Changed state to connected #1
DC-1 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 0 KB/s Sent: 0 KB/s
2021-04-10 19:54:54.481 INFO [16653] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-04-10 19:54:54.491 INFO [16627] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
2021-04-10 19:54:54.491 INFO [16627] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
State: connected State: connected
DataChannel from Okt4 open DataChannel from UDL4 open
2021-03-25 14:34:38.019 WARN [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101 #2
2021-03-25 14:34:38.019 WARN [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101 DC-1 Received: 84326 KB/s Sent: 0 KB/s BufferSize: 0
2021-03-25 14:34:38.019 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed TOTL Received: 84326 KB/s Sent: 0 KB/s
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful #3
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done DC-1 Received: 99387 KB/s Sent: 0 KB/s BufferSize: 0
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete TOTL Received: 99387 KB/s Sent: 0 KB/s
2021-04-10 19:54:57.025 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
2021-04-10 19:54:57.025 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
2021-04-10 19:54:57.025 INFO [16646] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
Gathering State: complete Gathering State: complete
2021-03-25 14:34:38.069 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed #4
#1 Received: 0 KB/s Sent: 92223 KB/s BufferSize: 65535 DC-1 Received: 94871 KB/s Sent: 0 KB/s BufferSize: 0
#2 Received: 0 KB/s Sent: 89291 KB/s BufferSize: 65535 TOTL Received: 94871 KB/s Sent: 0 KB/s
#3 Received: 0 KB/s Sent: 95087 KB/s BufferSize: 65535 #5
#4 Received: 0 KB/s Sent: 101050 KB/s BufferSize: 65535 DC-1 Received: 96259 KB/s Sent: 0 KB/s BufferSize: 0
#5 Received: 0 KB/s Sent: 99778 KB/s BufferSize: 0 TOTL Received: 96259 KB/s Sent: 0 KB/s
Stats# Received Total: 0 MB Sent Total: 480 MB RTT: 8 ms Stats# Received Total: 377 MB Sent Total: 0 MB RTT: 2 ms
#6 Received: 0 KB/s Sent: 100366 KB/s BufferSize: 65535 #6
#7 Received: 0 KB/s Sent: 101201 KB/s BufferSize: 65535 DC-1 Received: 92873 KB/s Sent: 0 KB/s BufferSize: 0
#8 Received: 0 KB/s Sent: 100892 KB/s BufferSize: 65535 TOTL Received: 92873 KB/s Sent: 0 KB/s
#9 Received: 0 KB/s Sent: 101288 KB/s BufferSize: 65535 #7
#10 Received: 0 KB/s Sent: 95676 KB/s BufferSize: 65535 DC-1 Received: 87724 KB/s Sent: 0 KB/s BufferSize: 0
Stats# Received Total: 0 MB Sent Total: 982 MB RTT: 8 ms TOTL Received: 87724 KB/s Sent: 0 KB/s
#8
DC-1 Received: 95123 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 95123 KB/s Sent: 0 KB/s
#9
DC-1 Received: 100022 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 100022 KB/s Sent: 0 KB/s
#10
DC-1 Received: 98124 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 98124 KB/s Sent: 0 KB/s
Stats# Received Total: 853 MB Sent Total: 0 MB RTT: 2 ms
#11 Received: 0 KB/s Sent: 96254 KB/s BufferSize: 65535 #11
#12 Received: 0 KB/s Sent: 105473 KB/s BufferSize: 65535 DC-1 Received: 103628 KB/s Sent: 0 KB/s BufferSize: 0
#13 Received: 0 KB/s Sent: 95549 KB/s BufferSize: 65535 TOTL Received: 103628 KB/s Sent: 0 KB/s
#14 Received: 0 KB/s Sent: 100366 KB/s BufferSize: 65535 #12
#15 Received: 0 KB/s Sent: 101336 KB/s BufferSize: 65535 DC-1 Received: 106166 KB/s Sent: 0 KB/s BufferSize: 0
Stats# Received Total: 0 MB Sent Total: 1484 MB RTT: 8 ms TOTL Received: 106166 KB/s Sent: 0 KB/s
#13
DC-1 Received: 98410 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 98410 KB/s Sent: 0 KB/s
#14
DC-1 Received: 99854 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 99854 KB/s Sent: 0 KB/s
#15
DC-1 Received: 98487 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 98487 KB/s Sent: 0 KB/s
Stats# Received Total: 1362 MB Sent Total: 0 MB RTT: 2 ms
``` ```
### Constant Throughput Set 8000 byte, for 300 seconds, send buffer 10000 byte ### Constant Throughput Set 8000 byte, for 300 seconds, send buffer 10000 byte
@ -159,61 +215,249 @@ Stats# Received Total: 0 MB Sent Total: 1484 MB RTT: 8 ms
Example Output (Offering Peer's Output); Example Output (Offering Peer's Output);
```bash ```bash
Stun server is stun:stun.l.google.com:19302 Stun server is stun:stun.l.google.com:19302
The local ID is: 1w9O The local ID is: 5zkC
Url is ws://localhost:8000/1w9O Url is ws://localhost:8000/5zkC
Waiting for signaling to be connected... Waiting for signaling to be connected...
2021-03-25 14:29:38.697 INFO [21844] [rtc::impl::TcpTransport::connect@159] Connected to localhost:8000 2021-04-10 19:52:49.788 INFO [16530] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-03-25 14:29:38.697 INFO [21844] [rtc::impl::TcpTransport::runLoop@327] TCP connected 2021-04-10 19:52:49.788 INFO [16530] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-03-25 14:29:38.698 INFO [21844] [rtc::impl::WsTransport::incoming@118] WebSocket open 2021-04-10 19:52:49.789 INFO [16530] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready WebSocket connected, signaling ready
Enter a remote ID to send an offer: Enter a remote ID to send an offer:
zi4B WawD
Offering to zi4B Offering to WawD
Creating DataChannel with label "benchmark" Creating DataChannel with label "DC-1"
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302" 2021-04-10 19:52:57.720 INFO [16523] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to new 2021-04-10 19:52:57.721 INFO [16523] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress 2021-04-10 19:52:57.721 INFO [16523] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
Gathering State: in-progress Gathering State: in-progress
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering 2021-04-10 19:52:57.722 INFO [16523] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
2021-03-25 14:29:48.730 WARN [21837] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:239: Local description already has the maximum number of host candidates
Benchmark will run for 300 seconds Benchmark will run for 300 seconds
2021-03-25 14:29:48.730 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting 2021-04-10 19:52:57.722 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
2021-03-25 14:29:48.731 INFO [21866] [rtc::impl::PeerConnection::changeState@964] Changed state to connecting 2021-04-10 19:52:57.722 INFO [16533] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
State: connecting State: connecting
2021-03-25 14:29:48.732 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302 2021-04-10 19:52:57.725 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
2021-03-25 14:29:48.732 INFO [21844] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to connecting 2021-04-10 19:52:57.727 INFO [16530] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-03-25 14:29:48.782 WARN [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101 2021-04-10 19:52:57.826 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-03-25 14:29:48.782 WARN [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101 2021-04-10 19:52:57.828 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
2021-03-25 14:29:48.782 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed 2021-04-10 19:52:57.829 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful 2021-04-10 19:52:57.884 INFO [16535] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done 2021-04-10 19:52:57.907 INFO [16526] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete 2021-04-10 19:52:57.907 INFO [16526] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
Gathering State: complete
2021-03-25 14:29:48.832 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-03-25 14:29:48.882 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
2021-03-25 14:29:49.735 INFO [21869] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-03-25 14:29:49.742 INFO [21841] [rtc::impl::SctpTransport::processNotification@708] SCTP connected
2021-03-25 14:29:49.742 INFO [21841] [rtc::impl::PeerConnection::changeState@964] Changed state to connected
State: connected State: connected
DataChannel from zi4B open DataChannel from WawD open
#1 Received: 0 KB/s Sent: 78 KB/s BufferSize: 0 #1
#2 Received: 8002 KB/s Sent: 7999 KB/s BufferSize: 0 DC-1 Received: 6515 KB/s Sent: 6577 KB/s BufferSize: 0
#3 Received: 8002 KB/s Sent: 7998 KB/s BufferSize: 0 TOTL Received: 6515 KB/s Sent: 6577 KB/s
#4 Received: 7995 KB/s Sent: 8000 KB/s BufferSize: 0 #2
#5 Received: 8000 KB/s Sent: 8001 KB/s BufferSize: 0 DC-1 Received: 7998 KB/s Sent: 7999 KB/s BufferSize: 0
Stats# Received Total: 33 MB Sent Total: 33 MB RTT: 0 ms TOTL Received: 7998 KB/s Sent: 7999 KB/s
#3
DC-1 Received: 7933 KB/s Sent: 7999 KB/s BufferSize: 0
TOTL Received: 7933 KB/s Sent: 7999 KB/s
2021-04-10 19:53:01.275 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
2021-04-10 19:53:01.275 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
2021-04-10 19:53:01.275 INFO [16533] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
Gathering State: complete
#4
DC-1 Received: 8070 KB/s Sent: 8000 KB/s BufferSize: 0
TOTL Received: 8070 KB/s Sent: 8000 KB/s
#5
DC-1 Received: 7984 KB/s Sent: 8000 KB/s BufferSize: 0
TOTL Received: 7984 KB/s Sent: 8000 KB/s
Stats# Received Total: 39 MB Sent Total: 39 MB RTT: 0 ms
#6 Received: 8001 KB/s Sent: 7999 KB/s BufferSize: 0 #6
#7 Received: 7997 KB/s Sent: 7998 KB/s BufferSize: 0 DC-1 Received: 8004 KB/s Sent: 7998 KB/s BufferSize: 0
#8 Received: 8001 KB/s Sent: 7999 KB/s BufferSize: 0 TOTL Received: 8004 KB/s Sent: 7998 KB/s
#9 Received: 7998 KB/s Sent: 8001 KB/s BufferSize: 0 #7
#10 Received: 8003 KB/s Sent: 7998 KB/s BufferSize: 0 DC-1 Received: 7997 KB/s Sent: 8000 KB/s BufferSize: 0
Stats# Received Total: 74 MB Sent Total: 74 MB RTT: 0 ms TOTL Received: 7997 KB/s Sent: 8000 KB/s
#8
DC-1 Received: 8008 KB/s Sent: 8000 KB/s BufferSize: 0
TOTL Received: 8008 KB/s Sent: 8000 KB/s
#9
DC-1 Received: 8007 KB/s Sent: 8000 KB/s BufferSize: 0
TOTL Received: 8007 KB/s Sent: 8000 KB/s
#10
DC-1 Received: 7999 KB/s Sent: 7999 KB/s BufferSize: 0
TOTL Received: 7999 KB/s Sent: 7999 KB/s
Stats# Received Total: 81 MB Sent Total: 81 MB RTT: 0 ms
#11 Received: 7990 KB/s Sent: 7998 KB/s BufferSize: 0 #11
#12 Received: 7999 KB/s Sent: 8000 KB/s BufferSize: 0 DC-1 Received: 7997 KB/s Sent: 8001 KB/s BufferSize: 0
#13 Received: 8001 KB/s Sent: 8002 KB/s BufferSize: 0 TOTL Received: 7997 KB/s Sent: 8001 KB/s
#14 Received: 7998 KB/s Sent: 7999 KB/s BufferSize: 0 #12
#15 Received: 8000 KB/s Sent: 7998 KB/s BufferSize: 0 DC-1 Received: 7981 KB/s Sent: 7997 KB/s BufferSize: 0
Stats# Received Total: 115 MB Sent Total: 115 MB RTT: 0 ms TOTL Received: 7981 KB/s Sent: 7997 KB/s
#13
DC-1 Received: 8024 KB/s Sent: 8000 KB/s BufferSize: 0
TOTL Received: 8024 KB/s Sent: 8000 KB/s
#14
DC-1 Received: 7990 KB/s Sent: 7999 KB/s BufferSize: 0
TOTL Received: 7990 KB/s Sent: 7999 KB/s
#15
DC-1 Received: 8001 KB/s Sent: 8002 KB/s BufferSize: 0
TOTL Received: 8001 KB/s Sent: 8002 KB/s
Stats# Received Total: 122 MB Sent Total: 122 MB RTT: 0 ms
```
### Constant Throughput Set 8000 byte, for 300 seconds, send buffer 10000 byte, 5 Data Channel
> `./client-benchmark -p -d 300 -r 8000 -b 10000 -c 5`
Example Output (Offering Peer's Output);
```bash
Stun server is stun:stun.l.google.com:19302
The local ID is: QZ46
Url is ws://localhost:8000/QZ46
Waiting for signaling to be connected...
2021-04-10 19:57:28.562 INFO [17117] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-04-10 19:57:28.562 INFO [17117] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-04-10 19:57:28.563 INFO [17117] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready
Enter a remote ID to send an offer:
lTZA
Offering to lTZA
Creating DataChannel with label "DC-1"
2021-04-10 19:57:37.371 INFO [17110] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-04-10 19:57:37.372 INFO [17110] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-04-10 19:57:37.373 INFO [17110] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
2021-04-10 19:57:37.373 INFO [17110] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
Gathering State: in-progress
Creating DataChannel with label "DC-2"
2021-04-10 19:57:37.373 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
Creating DataChannel with label "DC-3"
2021-04-10 19:57:37.374 INFO [17119] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
Creating DataChannel with label "DC-4"
Creating DataChannel with label "DC-5"
State: Benchmark will run for connecting300 seconds
2021-04-10 19:57:37.376 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
2021-04-10 19:57:37.378 INFO [17117] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-04-10 19:57:37.423 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
2021-04-10 19:57:37.476 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-04-10 19:57:37.478 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
2021-04-10 19:57:38.383 INFO [17122] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-04-10 19:57:38.392 INFO [17113] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
2021-04-10 19:57:38.392 INFO [17113] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
State: connected
DataChannel from lTZA open
DataChannel from lTZA open
#DataChannel from lTZA open
DataChannel from lTZA open
1
DC-5 Received: 0 KB/s Sent: 79 KB/s BufferSize: 0
DC-3 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
DC-4 Received: 0 KB/s Sent: 79 KB/s BufferSize: 0
DC-2 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
DC-1 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 0 KB/s Sent: 158 KB/s
DataChannel from lTZA open
#2
DC-5 Received: 7960 KB/s Sent: 8000 KB/s BufferSize: 0
DC-3 Received: 7804 KB/s Sent: 8000 KB/s BufferSize: 0
DC-4 Received: 7883 KB/s Sent: 8000 KB/s BufferSize: 0
DC-2 Received: 7882 KB/s Sent: 8000 KB/s BufferSize: 0
DC-1 Received: 7804 KB/s Sent: 8000 KB/s BufferSize: 0
TOTL Received: 39333 KB/s Sent: 40000 KB/s
#3
DC-5 Received: 7966 KB/s Sent: 7996 KB/s BufferSize: 81504
DC-3 Received: 8047 KB/s Sent: 7996 KB/s BufferSize: 81504
DC-4 Received: 7958 KB/s Sent: 7996 KB/s BufferSize: 81504
DC-2 Received: 7958 KB/s Sent: 7996 KB/s BufferSize: 81504
DC-1 Received: 8067 KB/s Sent: 7996 KB/s BufferSize: 163597
TOTL Received: 39996 KB/s Sent: 39980 KB/s
2021-04-10 19:57:40.926 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
2021-04-10 19:57:40.926 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
2021-04-10 19:57:40.926 INFO [17119] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
Gathering State: complete
#4
DC-5 Received: 7970 KB/s Sent: 8002 KB/s BufferSize: 0
DC-3 Received: 7957 KB/s Sent: 8002 KB/s BufferSize: 0
DC-4 Received: 7910 KB/s Sent: 8002 KB/s BufferSize: 0
DC-2 Received: 7967 KB/s Sent: 8002 KB/s BufferSize: 0
DC-1 Received: 7957 KB/s Sent: 8002 KB/s BufferSize: 0
TOTL Received: 39761 KB/s Sent: 40010 KB/s
#5
DC-5 Received: 7996 KB/s Sent: 7999 KB/s BufferSize: 0
DC-3 Received: 8006 KB/s Sent: 7999 KB/s BufferSize: 0
DC-4 Received: 8078 KB/s Sent: 7999 KB/s BufferSize: 0
DC-2 Received: 8015 KB/s Sent: 7999 KB/s BufferSize: 0
DC-1 Received: 7928 KB/s Sent: 7999 KB/s BufferSize: 0
TOTL Received: 40023 KB/s Sent: 39995 KB/s
Stats# Received Total: 165 MB Sent Total: 166 MB RTT: 1 ms
#6
DC-5 Received: 7968 KB/s Sent: 7999 KB/s BufferSize: 0
DC-3 Received: 7962 KB/s Sent: 7999 KB/s BufferSize: 0
DC-4 Received: 7965 KB/s Sent: 7999 KB/s BufferSize: 0
DC-2 Received: 7970 KB/s Sent: 7999 KB/s BufferSize: 0
DC-1 Received: 8044 KB/s Sent: 7999 KB/s BufferSize: 0
TOTL Received: 39909 KB/s Sent: 39995 KB/s
#7
DC-5 Received: 6658 KB/s Sent: 8001 KB/s BufferSize: 82228
DC-3 Received: 6584 KB/s Sent: 8001 KB/s BufferSize: 163596
DC-4 Received: 6572 KB/s Sent: 8001 KB/s BufferSize: 163596
DC-2 Received: 6571 KB/s Sent: 8001 KB/s BufferSize: 163596
DC-1 Received: 6492 KB/s Sent: 8001 KB/s BufferSize: 163596
TOTL Received: 32877 KB/s Sent: 40005 KB/s
#8
DC-5 Received: 5773 KB/s Sent: 7997 KB/s BufferSize: 0
DC-3 Received: 6555 KB/s Sent: 7997 KB/s BufferSize: 0
DC-4 Received: 6164 KB/s Sent: 7997 KB/s BufferSize: 0
DC-2 Received: 6241 KB/s Sent: 7997 KB/s BufferSize: 0
DC-1 Received: 5454 KB/s Sent: 7997 KB/s BufferSize: 0
TOTL Received: 30187 KB/s Sent: 39985 KB/s
#9
DC-5 Received: 7442 KB/s Sent: 8002 KB/s BufferSize: 326921
DC-3 Received: 7580 KB/s Sent: 8002 KB/s BufferSize: 326921
DC-4 Received: 7363 KB/s Sent: 8002 KB/s BufferSize: 326921
DC-2 Received: 7524 KB/s Sent: 8002 KB/s BufferSize: 326921
DC-1 Received: 7362 KB/s Sent: 8002 KB/s BufferSize: 408769
TOTL Received: 37271 KB/s Sent: 40010 KB/s
#10
DC-5 Received: 6134 KB/s Sent: 7999 KB/s BufferSize: 244963
DC-3 Received: 8032 KB/s Sent: 7999 KB/s BufferSize: 326286
DC-4 Received: 5897 KB/s Sent: 7999 KB/s BufferSize: 326286
DC-2 Received: 5657 KB/s Sent: 7999 KB/s BufferSize: 326286
DC-1 Received: 5581 KB/s Sent: 7999 KB/s BufferSize: 326286
TOTL Received: 31301 KB/s Sent: 39995 KB/s
Stats# Received Total: 343 MB Sent Total: 372 MB RTT: 16 ms
#11
DC-5 Received: 6117 KB/s Sent: 7998 KB/s BufferSize: 570756
DC-3 Received: 6594 KB/s Sent: 7998 KB/s BufferSize: 570756
DC-4 Received: 6354 KB/s Sent: 7998 KB/s BufferSize: 570756
DC-2 Received: 6116 KB/s Sent: 7998 KB/s BufferSize: 570756
DC-1 Received: 5959 KB/s Sent: 7998 KB/s BufferSize: 570756
TOTL Received: 31140 KB/s Sent: 39990 KB/s
#12
DC-5 Received: 6840 KB/s Sent: 7999 KB/s BufferSize: 0
DC-3 Received: 7468 KB/s Sent: 7999 KB/s BufferSize: 0
DC-4 Received: 7472 KB/s Sent: 7999 KB/s BufferSize: 0
DC-2 Received: 7473 KB/s Sent: 7999 KB/s BufferSize: 0
DC-1 Received: 7236 KB/s Sent: 7999 KB/s BufferSize: 0
TOTL Received: 36489 KB/s Sent: 39995 KB/s
#13
DC-5 Received: 8105 KB/s Sent: 7989 KB/s BufferSize: 0
DC-3 Received: 8020 KB/s Sent: 7989 KB/s BufferSize: 0
DC-4 Received: 8097 KB/s Sent: 7989 KB/s BufferSize: 0
DC-2 Received: 8106 KB/s Sent: 7989 KB/s BufferSize: 0
DC-1 Received: 8018 KB/s Sent: 7989 KB/s BufferSize: 0
TOTL Received: 40346 KB/s Sent: 39945 KB/s
#14
DC-5 Received: 8042 KB/s Sent: 8007 KB/s BufferSize: 0
DC-3 Received: 8029 KB/s Sent: 8007 KB/s BufferSize: 0
DC-4 Received: 8038 KB/s Sent: 8007 KB/s BufferSize: 0
DC-2 Received: 8035 KB/s Sent: 8007 KB/s BufferSize: 0
DC-1 Received: 8036 KB/s Sent: 8007 KB/s BufferSize: 0
TOTL Received: 40180 KB/s Sent: 40035 KB/s
#15
DC-5 Received: 7981 KB/s Sent: 8001 KB/s BufferSize: 0
DC-3 Received: 7987 KB/s Sent: 8001 KB/s BufferSize: 0
DC-4 Received: 7980 KB/s Sent: 8001 KB/s BufferSize: 0
DC-2 Received: 7974 KB/s Sent: 8001 KB/s BufferSize: 0
DC-1 Received: 7972 KB/s Sent: 8001 KB/s BufferSize: 82497
TOTL Received: 39894 KB/s Sent: 40005 KB/s
Stats# Received Total: 538 MB Sent Total: 581 MB RTT: 3 ms
``` ```

View File

@ -31,6 +31,7 @@
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <future> #include <future>
#include <iomanip>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <random> #include <random>
@ -61,7 +62,8 @@ string randomId(size_t length);
// Benchmark // Benchmark
const size_t messageSize = 65535; const size_t messageSize = 65535;
binary messageData(messageSize); binary messageData(messageSize);
atomic<size_t> receivedSize = 0, sentSize = 0; unordered_map<string, atomic<size_t>> receivedSizeMap;
unordered_map<string, atomic<size_t>> sentSizeMap;
bool noSend = false; bool noSend = false;
// Benchmark - enableThroughputSet params // Benchmark - enableThroughputSet params
@ -69,7 +71,7 @@ bool enableThroughputSet;
int throughtputSetAsKB; int throughtputSetAsKB;
int bufferSize; int bufferSize;
const float STEP_COUNT_FOR_1_SEC = 100.0; const float STEP_COUNT_FOR_1_SEC = 100.0;
const int stepDurationInMs = 1000 / STEP_COUNT_FOR_1_SEC; const int stepDurationInMs = int(1000 / STEP_COUNT_FOR_1_SEC);
int main(int argc, char **argv) try { int main(int argc, char **argv) try {
Cmdline params(argc, argv); Cmdline params(argc, argv);
@ -188,63 +190,67 @@ int main(int argc, char **argv) try {
auto pc = createPeerConnection(config, ws, id); auto pc = createPeerConnection(config, ws, id);
// We are the offerer, so create a data channel to initiate the process // We are the offerer, so create a data channel to initiate the process
const string label = "benchmark"; for (int i = 1; i <= params.dataChannelCount(); i++) {
cout << "Creating DataChannel with label \"" << label << "\"" << endl; const string label = "DC-" + std::to_string(i);
auto dc = pc->createDataChannel(label); cout << "Creating DataChannel with label \"" << label << "\"" << endl;
auto dc = pc->createDataChannel(label);
receivedSizeMap.emplace(label, 0);
sentSizeMap.emplace(label, 0);
// Set Buffer Size // Set Buffer Size
dc->setBufferedAmountLowThreshold(bufferSize); dc->setBufferedAmountLowThreshold(bufferSize);
dc->onOpen([id, wdc = make_weak_ptr(dc)]() { dc->onOpen([id, wdc = make_weak_ptr(dc), label]() {
cout << "DataChannel from " << id << " open" << endl; cout << "DataChannel from " << id << " open" << endl;
if (noSend) if (noSend)
return; return;
if (enableThroughputSet) if (enableThroughputSet)
return; return;
if (auto dcLocked = wdc.lock()) { if (auto dcLocked = wdc.lock()) {
try {
while (dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(messageData);
sentSizeMap.at(label) += messageData.size();
}
} catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl;
}
}
});
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc), label]() {
if (noSend)
return;
if (enableThroughputSet)
return;
auto dcLocked = wdc.lock();
if (!dcLocked)
return;
// Continue sending
try { try {
while (dcLocked->bufferedAmount() <= bufferSize) { while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(messageData); dcLocked->send(messageData);
sentSize += messageData.size(); sentSizeMap.at(label) += messageData.size();
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl; std::cout << "Send failed: " << e.what() << std::endl;
} }
} });
});
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc)]() { dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
if (noSend)
return;
if (enableThroughputSet) dc->onMessage([id, wdc = make_weak_ptr(dc), label](variant<binary, string> data) {
return; if (holds_alternative<binary>(data))
receivedSizeMap.at(label) += get<binary>(data).size();
});
auto dcLocked = wdc.lock(); dataChannelMap.emplace(label, dc);
if (!dcLocked) }
return;
// Continue sending
try {
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(messageData);
sentSize += messageData.size();
}
} catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl;
}
});
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
dc->onMessage([id, wdc = make_weak_ptr(dc)](variant<binary, string> data) {
if (holds_alternative<binary>(data))
receivedSize += get<binary>(data).size();
});
dataChannelMap.emplace(id, dc);
const int duration = params.durationInSec() > 0 ? params.durationInSec() : INT32_MAX; const int duration = params.durationInSec() > 0 ? params.durationInSec() : INT32_MAX;
cout << "Benchmark will run for " << duration << " seconds" << endl; cout << "Benchmark will run for " << duration << " seconds" << endl;
@ -271,25 +277,39 @@ int main(int argc, char **argv) try {
binary tempMessageData(byteToSendThisLoop); binary tempMessageData(byteToSendThisLoop);
fill(tempMessageData.begin(), tempMessageData.end(), std::byte(0xFF)); fill(tempMessageData.begin(), tempMessageData.end(), std::byte(0xFF));
if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) { for (const auto &[label, dc] : dataChannelMap) {
dc->send(tempMessageData); if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) {
sentSize += tempMessageData.size(); dc->send(tempMessageData);
sentSizeMap.at(label) += tempMessageData.size();
}
} }
} }
if (printCounter >= STEP_COUNT_FOR_1_SEC) { if (printCounter >= STEP_COUNT_FOR_1_SEC) {
unsigned long _receivedSize = receivedSize.exchange(0);
unsigned long _sentSize = sentSize.exchange(0);
const double elapsedTimeInSecs = const double elapsedTimeInSecs =
std::chrono::duration<double>(steady_clock::now() - printTime).count(); std::chrono::duration<double>(steady_clock::now() - printTime).count();
printTime = steady_clock::now(); printTime = steady_clock::now();
cout << "#" << i / STEP_COUNT_FOR_1_SEC unsigned long receiveSpeedTotal = 0;
<< " Received: " << static_cast<int>(_receivedSize / (elapsedTimeInSecs * 1000)) unsigned long sendSpeedTotal = 0;
<< " KB/s" cout << "#" << i / STEP_COUNT_FOR_1_SEC << endl;
<< " Sent: " << static_cast<int>(_sentSize / (elapsedTimeInSecs * 1000)) for (const auto &[label, dc] : dataChannelMap) {
<< " KB/s" unsigned long channelReceiveSpeed = static_cast<int>(
<< " BufferSize: " << dc->bufferedAmount() << endl; receivedSizeMap[label].exchange(0) / (elapsedTimeInSecs * 1000));
unsigned long channelSendSpeed =
static_cast<int>(sentSizeMap[label].exchange(0) / (elapsedTimeInSecs * 1000));
cout << std::setw(10) << label << " Received: " << channelReceiveSpeed << " KB/s"
<< " Sent: " << channelSendSpeed << " KB/s"
<< " BufferSize: " << dc->bufferedAmount() << endl;
receiveSpeedTotal += channelReceiveSpeed;
sendSpeedTotal += channelSendSpeed;
}
cout << std::setw(10) << "TOTL"
<< " Received: " << receiveSpeedTotal << " KB/s"
<< " Sent: " << sendSpeedTotal << " KB/s" << endl;
printStatCounter++; printStatCounter++;
printCounter = 0; printCounter = 0;
} }
@ -308,12 +328,16 @@ int main(int argc, char **argv) try {
dataChannelMap.clear(); dataChannelMap.clear();
peerConnectionMap.clear(); peerConnectionMap.clear();
receivedSizeMap.clear();
sentSizeMap.clear();
return 0; return 0;
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cout << "Error: " << e.what() << std::endl; std::cout << "Error: " << e.what() << std::endl;
dataChannelMap.clear(); dataChannelMap.clear();
peerConnectionMap.clear(); peerConnectionMap.clear();
receivedSizeMap.clear();
sentSizeMap.clear();
return -1; return -1;
} }
@ -346,13 +370,16 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
}); });
pc->onDataChannel([id](shared_ptr<DataChannel> dc) { pc->onDataChannel([id](shared_ptr<DataChannel> dc) {
cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\"" const string label = dc->label();
<< endl; cout << "DataChannel from " << id << " received with label \"" << label << "\"" << endl;
cout << "###########################################" << endl; cout << "###########################################" << endl;
cout << "### Check other peer's screen for stats ###" << endl; cout << "### Check other peer's screen for stats ###" << endl;
cout << "###########################################" << endl; cout << "###########################################" << endl;
receivedSizeMap.emplace(dc->label(), 0);
sentSizeMap.emplace(dc->label(), 0);
// Set Buffer Size // Set Buffer Size
dc->setBufferedAmountLowThreshold(bufferSize); dc->setBufferedAmountLowThreshold(bufferSize);
@ -360,7 +387,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
try { try {
while (dc->bufferedAmount() <= bufferSize) { while (dc->bufferedAmount() <= bufferSize) {
dc->send(messageData); dc->send(messageData);
sentSize += messageData.size(); sentSizeMap.at(label) += messageData.size();
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl; std::cout << "Send failed: " << e.what() << std::endl;
@ -370,7 +397,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
if (!noSend && enableThroughputSet) { if (!noSend && enableThroughputSet) {
// Create Send Data Thread // Create Send Data Thread
// Thread will join when data channel destroyed or closed // Thread will join when data channel destroyed or closed
std::thread([wdc = make_weak_ptr(dc)]() { std::thread([wdc = make_weak_ptr(dc), label]() {
steady_clock::time_point stepTime = steady_clock::now(); steady_clock::time_point stepTime = steady_clock::now();
// Byte count to send for every loop // Byte count to send for every loop
int byteToSendOnEveryLoop = throughtputSetAsKB * stepDurationInMs; int byteToSendOnEveryLoop = throughtputSetAsKB * stepDurationInMs;
@ -399,7 +426,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
if (dcLocked->bufferedAmount() <= bufferSize) { if (dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(tempMessageData); dcLocked->send(tempMessageData);
sentSize += tempMessageData.size(); sentSizeMap.at(label) += tempMessageData.size();
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl; std::cout << "Send failed: " << e.what() << std::endl;
@ -409,7 +436,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
}).detach(); }).detach();
} }
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc)]() { dc->onBufferedAmountLow([wdc = make_weak_ptr(dc), label]() {
if (noSend) if (noSend)
return; return;
@ -424,7 +451,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
try { try {
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) { while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(messageData); dcLocked->send(messageData);
sentSize += messageData.size(); sentSizeMap.at(label) += messageData.size();
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl; std::cout << "Send failed: " << e.what() << std::endl;
@ -433,12 +460,12 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; }); dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
dc->onMessage([id, wdc = make_weak_ptr(dc)](variant<binary, string> data) { dc->onMessage([id, wdc = make_weak_ptr(dc), label](variant<binary, string> data) {
if (holds_alternative<binary>(data)) if (holds_alternative<binary>(data))
receivedSize += get<binary>(data).size(); receivedSizeMap.at(label) += get<binary>(data).size();
}); });
dataChannelMap.emplace(id, dc); dataChannelMap.emplace(label, dc);
}); });
peerConnectionMap.emplace(id, pc); peerConnectionMap.emplace(id, pc);

View File

@ -51,6 +51,7 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
{"enableThroughputSet", no_argument, NULL, 'p'}, {"enableThroughputSet", no_argument, NULL, 'p'},
{"throughtputSetAsKB", required_argument, NULL, 'r'}, {"throughtputSetAsKB", required_argument, NULL, 'r'},
{"bufferSize", required_argument, NULL, 'b'}, {"bufferSize", required_argument, NULL, 'b'},
{"dataChannelCount", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}}; {NULL, 0, NULL, 0}};
@ -68,9 +69,10 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
_p = false; _p = false;
_r = 300; _r = 300;
_b = 0; _b = 0;
_c = 1;
optind = 0; optind = 0;
while ((c = getopt_long(argc, argv, "s:t:w:x:d:r:b:enhvop", long_options, &optind)) != -1) { while ((c = getopt_long(argc, argv, "s:t:w:x:d:r:b:c:enhvop", long_options, &optind)) != -1) {
switch (c) { switch (c) {
case 'n': case 'n':
_n = true; _n = true;
@ -147,6 +149,15 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
} }
break; break;
case 'c':
_c = atoi(optarg);
if (_c <= 0) {
std::string err;
err += "parameter range error: c must be > 0";
throw(std::range_error(err));
}
break;
case 'h': case 'h':
_h = true; _h = true;
this->usage(EXIT_SUCCESS); this->usage(EXIT_SUCCESS);
@ -196,6 +207,8 @@ libdatachannel client implementing WebRTC Data Channels with WebSocket signaling
Send a constant data per second (KB). See throughtputSetAsKB params.\n\ Send a constant data per second (KB). See throughtputSetAsKB params.\n\
[ -r ] [ --throughtputSetAsKB ] (type=INTEGER, range>0...INT_MAX, default=300)\n\ [ -r ] [ --throughtputSetAsKB ] (type=INTEGER, range>0...INT_MAX, default=300)\n\
Send constant data per second (KB).\n\ Send constant data per second (KB).\n\
[ -c ] [ --dataChannelCount ] (type=INTEGER, range>0...INT_MAX, default=1)\n\
Dat Channel count to create.\n\
[ -h ] [ --help ] (type=FLAG)\n\ [ -h ] [ --help ] (type=FLAG)\n\
Display this help and exit.\n"; Display this help and exit.\n";
} }

View File

@ -45,6 +45,7 @@ private:
bool _p; bool _p;
int _r; int _r;
int _b; int _b;
int _c;
/* other stuff to keep track of */ /* other stuff to keep track of */
std::string _program_name; std::string _program_name;
@ -69,9 +70,10 @@ public:
bool h () const { return _h; } bool h () const { return _h; }
int durationInSec () const { return _d; } int durationInSec () const { return _d; }
bool noSend () const { return _o; } bool noSend () const { return _o; }
int bufferSize() const { return _b;} int bufferSize() const { return _b; }
bool enableThroughputSet () const { return _p; } bool enableThroughputSet () const { return _p; }
int throughtputSetAsKB() const { return _r;} int throughtputSetAsKB() const { return _r; }
int dataChannelCount() const { return _c; }
}; };
#endif #endif

View File

@ -222,9 +222,14 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\"" cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
<< endl; << endl;
dc->onOpen([wdc = make_weak_ptr(dc)]() {
if (auto dc = wdc.lock())
dc->send("Hello from " + localId);
});
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; }); dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
dc->onMessage([id, wdc = make_weak_ptr(dc)](variant<binary, string> data) { dc->onMessage([id](variant<binary, string> data) {
if (holds_alternative<string>(data)) if (holds_alternative<string>(data))
cout << "Message from " << id << " received: " << get<string>(data) << endl; cout << "Message from " << id << " received: " << get<string>(data) << endl;
else else
@ -232,8 +237,6 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
<< " received, size=" << get<binary>(data).size() << endl; << " received, size=" << get<binary>(data).size() << endl;
}); });
dc->send("Hello from " + localId);
dataChannelMap.emplace(id, dc); dataChannelMap.emplace(id, dc);
}); });
@ -251,4 +254,3 @@ string randomId(size_t length) {
generate(id.begin(), id.end(), [&]() { return characters.at(dist(rng)); }); generate(id.begin(), id.end(), [&]() { return characters.at(dist(rng)); });
return id; return id;
} }

View File

@ -9,7 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "GPL-2.0", "license": "GPL-2.0",
"dependencies": { "dependencies": {
"websocket": "^1.0.33" "websocket": "^1.0.34"
} }
}, },
"node_modules/bufferutil": { "node_modules/bufferutil": {
@ -128,9 +128,9 @@
} }
}, },
"node_modules/websocket": { "node_modules/websocket": {
"version": "1.0.33", "version": "1.0.34",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.33.tgz", "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
"integrity": "sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==", "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
"dependencies": { "dependencies": {
"bufferutil": "^4.0.1", "bufferutil": "^4.0.1",
"debug": "^2.2.0", "debug": "^2.2.0",
@ -264,9 +264,9 @@
} }
}, },
"websocket": { "websocket": {
"version": "1.0.33", "version": "1.0.34",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.33.tgz", "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
"integrity": "sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==", "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
"requires": { "requires": {
"bufferutil": "^4.0.1", "bufferutil": "^4.0.1",
"debug": "^2.2.0", "debug": "^2.2.0",

View File

@ -2,7 +2,7 @@
"name": "libdatachannel-signaling-server", "name": "libdatachannel-signaling-server",
"version": "0.1.0", "version": "0.1.0",
"description": "Signaling server example for libdatachannel", "description": "Signaling server example for libdatachannel",
"main": "server.js", "main": "signaling-server.js",
"scripts": { "scripts": {
"start": "node signaling-server.js", "start": "node signaling-server.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
@ -18,6 +18,6 @@
}, },
"homepage": "https://github.com/paullouisageneau/libdatachannel#readme", "homepage": "https://github.com/paullouisageneau/libdatachannel#readme",
"dependencies": { "dependencies": {
"websocket": "^1.0.33" "websocket": "^1.0.34"
} }
} }

View File

@ -17,7 +17,6 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>. * along with this program; If not, see <http://www.gnu.org/licenses/>.
*/ */
const fs = require('fs');
const http = require('http'); const http = require('http');
const websocket = require('websocket'); const websocket = require('websocket');

View File

@ -17,9 +17,16 @@
*/ */
#include "h264fileparser.hpp" #include "h264fileparser.hpp"
#include <fstream>
#include "rtc/rtc.hpp" #include "rtc/rtc.hpp"
#include <fstream>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
using namespace std; using namespace std;
H264FileParser::H264FileParser(string directory, uint32_t fps, bool loop): FileParser(directory, ".h264", fps, loop) { } H264FileParser::H264FileParser(string directory, uint32_t fps, bool loop): FileParser(directory, ".h264", fps, loop) { }

View File

@ -19,10 +19,10 @@
#include "helpers.hpp" #include "helpers.hpp"
#include <ctime> #include <ctime>
#if _WIN32 #ifdef _WIN32
// taken from https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows // taken from https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows
#include <windows.h>
#include <Windows.h> #include <winsock2.h> // for struct timeval
struct timezone { struct timezone {
int tz_minuteswest; int tz_minuteswest;
@ -55,6 +55,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
} }
return 0; return 0;
} }
#else
#include <sys/time.h>
#endif #endif
using namespace std; using namespace std;

View File

@ -218,11 +218,11 @@ shared_ptr<ClientTrackData> addVideo(const shared_ptr<PeerConnection> pc, const
video.addSSRC(ssrc, cname, msid, cname); video.addSSRC(ssrc, cname, msid, cname);
auto track = pc->addTrack(video); auto track = pc->addTrack(video);
// create RTP configuration // create RTP configuration
auto rtpConfig = shared_ptr<RtpPacketizationConfig>(new RtpPacketizationConfig(ssrc, cname, payloadType, H264RtpPacketizer::defaultClockRate)); auto rtpConfig = make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, H264RtpPacketizer::defaultClockRate);
// create packetizer // create packetizer
auto packetizer = shared_ptr<H264RtpPacketizer>(new H264RtpPacketizer(H264RtpPacketizer::Separator::Length, rtpConfig)); auto packetizer = make_shared<H264RtpPacketizer>(H264RtpPacketizer::Separator::Length, rtpConfig);
// create H264 handler // create H264 handler
shared_ptr<H264PacketizationHandler> h264Handler(new H264PacketizationHandler(packetizer)); auto h264Handler = make_shared<H264PacketizationHandler>(packetizer);
// add RTCP SR handler // add RTCP SR handler
auto srReporter = make_shared<RtcpSrReporter>(rtpConfig); auto srReporter = make_shared<RtcpSrReporter>(rtpConfig);
h264Handler->addToChain(srReporter); h264Handler->addToChain(srReporter);
@ -242,7 +242,7 @@ shared_ptr<ClientTrackData> addAudio(const shared_ptr<PeerConnection> pc, const
audio.addSSRC(ssrc, cname, msid, cname); audio.addSSRC(ssrc, cname, msid, cname);
auto track = pc->addTrack(audio); auto track = pc->addTrack(audio);
// create RTP configuration // create RTP configuration
auto rtpConfig = shared_ptr<RtpPacketizationConfig>(new RtpPacketizationConfig(ssrc, cname, payloadType, OpusRtpPacketizer::defaultClockRate)); auto rtpConfig = make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, OpusRtpPacketizer::defaultClockRate);
// create packetizer // create packetizer
auto packetizer = make_shared<OpusRtpPacketizer>(rtpConfig); auto packetizer = make_shared<OpusRtpPacketizer>(rtpConfig);
// create opus handler // create opus handler
@ -265,7 +265,7 @@ shared_ptr<Client> createPeerConnection(const Configuration &config,
weak_ptr<WebSocket> wws, weak_ptr<WebSocket> wws,
string id) { string id) {
auto pc = make_shared<PeerConnection>(config); auto pc = make_shared<PeerConnection>(config);
shared_ptr<Client> client(new Client(pc)); auto client = make_shared<Client>(pc);
pc->onStateChange([id](PeerConnection::State state) { pc->onStateChange([id](PeerConnection::State state) {
cout << "State: " << state << endl; cout << "State: " << state << endl;

View File

@ -19,7 +19,7 @@
#include "stream.hpp" #include "stream.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#if _WIN32 #ifdef _WIN32
// taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw // taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw
#include <windows.h> #include <windows.h>
@ -35,6 +35,8 @@ void usleep(__int64 usec)
WaitForSingleObject(timer, INFINITE); WaitForSingleObject(timer, INFINITE);
CloseHandle(timer); CloseHandle(timer);
} }
#else
#include <unistd.h>
#endif #endif
void StreamSource::stop() { void StreamSource::stop() {

View File

@ -118,7 +118,7 @@ function createPeerConnection(ws, id) {
pc.onconnectionstatechange = () => console.log(`Connection state: ${pc.connectionState}`); pc.onconnectionstatechange = () => console.log(`Connection state: ${pc.connectionState}`);
pc.onicegatheringstatechange = () => console.log(`Gathering state: ${pc.iceGatheringState}`); pc.onicegatheringstatechange = () => console.log(`Gathering state: ${pc.iceGatheringState}`);
pc.onicecandidate = (e) => { pc.onicecandidate = (e) => {
if (e.candidate) { if (e.candidate && e.candidate.candidate) {
// Send candidate // Send candidate
sendLocalCandidate(ws, id, e.candidate); sendLocalCandidate(ws, id, e.candidate);
} }

View File

@ -41,7 +41,6 @@
#include "rtc.h" // for C API defines #include "rtc.h" // for C API defines
#include "log.hpp"
#include "utils.hpp" #include "utils.hpp"
#include <cstddef> #include <cstddef>
@ -70,6 +69,7 @@ using binary = std::vector<byte>;
using binary_ptr = std::shared_ptr<binary>; using binary_ptr = std::shared_ptr<binary>;
using std::size_t; using std::size_t;
using std::ptrdiff_t;
using std::uint16_t; using std::uint16_t;
using std::uint32_t; using std::uint32_t;
using std::uint64_t; using std::uint64_t;

View File

@ -42,7 +42,14 @@ class RTC_CPP_EXPORT Description {
public: public:
enum class Type { Unspec, Offer, Answer, Pranswer, Rollback }; enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
enum class Role { ActPass, Passive, Active }; enum class Role { ActPass, Passive, Active };
enum class Direction { SendOnly, RecvOnly, SendRecv, Inactive, Unknown };
enum class Direction {
SendOnly = RTC_DIRECTION_SENDONLY,
RecvOnly = RTC_DIRECTION_RECVONLY,
SendRecv = RTC_DIRECTION_SENDRECV,
Inactive = RTC_DIRECTION_INACTIVE,
Unknown = RTC_DIRECTION_UNKNOWN
};
Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass); Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass);
Description(const string &sdp, string typeString); Description(const string &sdp, string typeString);

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2019 Paul-Louis Ageneau * Copyright (c) 2020-2021 Paul-Louis Ageneau
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -16,27 +16,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_LOG_H #ifndef RTC_GLOBAL_H
#define RTC_LOG_H #define RTC_GLOBAL_H
// Disable warnings before including plog
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#elif defined(_MSC_VER)
#pragma warning(push, 0)
#endif
#include "plog/Log.h"
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif
#include "common.hpp" #include "common.hpp"
#include <chrono>
#include <iostream>
namespace rtc { namespace rtc {
enum class LogLevel { // Don't change, it must match plog severity enum class LogLevel { // Don't change, it must match plog severity
@ -49,8 +36,31 @@ enum class LogLevel { // Don't change, it must match plog severity
Verbose = 6 Verbose = 6
}; };
RTC_CPP_EXPORT void InitLogger(LogLevel level); typedef std::function<void(LogLevel level, string message)> LogCallback;
RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr);
#ifdef PLOG
RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr); RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
#endif
RTC_CPP_EXPORT void Preload();
RTC_CPP_EXPORT void Cleanup();
struct SctpSettings {
// For the following settings, not set means optimized default
optional<size_t> recvBufferSize; // in bytes
optional<size_t> sendBufferSize; // in bytes
optional<size_t> maxChunksOnQueue; // in chunks
optional<size_t> initialCongestionWindow; // in MTUs
optional<size_t> maxBurst; // in MTUs
optional<unsigned int> congestionControlModule; // 0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC
optional<std::chrono::milliseconds> delayedSackTime;
};
RTC_CPP_EXPORT void SetSctpSettings(SctpSettings s);
} // namespace rtc } // namespace rtc
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level);
#endif #endif

View File

@ -1,23 +1,23 @@
/* /**
* libdatachannel client example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef H264_PACKETIZATION_HANDLER_H #ifndef RTC_H264_PACKETIZATION_HANDLER_H
#define H264_PACKETIZATION_HANDLER_H #define RTC_H264_PACKETIZATION_HANDLER_H
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
@ -28,7 +28,7 @@
namespace rtc { namespace rtc {
/// Handler for H264 packetization /// Handler for H264 packetization
class RTC_CPP_EXPORT H264PacketizationHandler : public MediaChainableHandler { class RTC_CPP_EXPORT H264PacketizationHandler final : public MediaChainableHandler {
public: public:
/// Construct handler for H264 packetization. /// Construct handler for H264 packetization.
/// @param packetizer RTP packetizer for h264 /// @param packetizer RTP packetizer for h264
@ -39,4 +39,4 @@ public:
#endif /* RTC_ENABLE_MEDIA */ #endif /* RTC_ENABLE_MEDIA */
#endif /* H264_PACKETIZATION_HANDLER_H */ #endif /* RTC_H264_PACKETIZATION_HANDLER_H */

View File

@ -1,23 +1,23 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef H264_RTP_PACKETIZER_H #ifndef RTC_H264_RTP_PACKETIZER_H
#define H264_RTP_PACKETIZER_H #define RTC_H264_RTP_PACKETIZER_H
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
@ -28,13 +28,13 @@
namespace rtc { namespace rtc {
/// RTP packetization of h264 payload /// RTP packetization of h264 payload
class RTC_CPP_EXPORT H264RtpPacketizer : public RtpPacketizer, public MediaHandlerRootElement { class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement {
shared_ptr<NalUnits> splitMessage(binary_ptr message); shared_ptr<NalUnits> splitMessage(binary_ptr message);
const uint16_t maximumFragmentSize; const uint16_t maximumFragmentSize;
public: public:
/// Default clock rate for H264 in RTP /// Default clock rate for H264 in RTP
static const auto defaultClockRate = 90 * 1000; inline static const uint32_t defaultClockRate = 90 * 1000;
/// Nalunit separator /// Nalunit separator
enum class Separator { enum class Separator {
@ -64,4 +64,4 @@ private:
#endif /* RTC_ENABLE_MEDIA */ #endif /* RTC_ENABLE_MEDIA */
#endif /* H264_RTP_PACKETIZER_H */ #endif /* RTC_H264_RTP_PACKETIZER_H */

View File

@ -1,18 +1,19 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_MEDIA_CHAINABLE_HANDLER_H #ifndef RTC_MEDIA_CHAINABLE_HANDLER_H

View File

@ -1,18 +1,19 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_MEDIA_HANDLER_ELEMENT_H #ifndef RTC_MEDIA_HANDLER_ELEMENT_H

View File

@ -1,22 +1,23 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H #ifndef RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
#define RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H #define RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
@ -42,4 +43,4 @@ public:
#endif // RTC_ENABLE_MEDIA #endif // RTC_ENABLE_MEDIA
#endif // RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H #endif // RTC_MEDIA_HANDLER_ROOT_ELEMENT_H

View File

@ -1,34 +1,38 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef NAL_UNIT_H #ifndef RTC_NAL_UNIT_H
#define NAL_UNIT_H #define RTC_NAL_UNIT_H
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "common.hpp" #include "common.hpp"
#include <cassert>
namespace rtc { namespace rtc {
#pragma pack(push, 1) #pragma pack(push, 1)
/// Nalu header /// Nalu header
struct RTC_CPP_EXPORT NalUnitHeader { struct RTC_CPP_EXPORT NalUnitHeader {
uint8_t _first = 0;
bool forbiddenBit() { return _first >> 7; } bool forbiddenBit() { return _first >> 7; }
uint8_t nri() { return _first >> 5 & 0x03; } uint8_t nri() { return _first >> 5 & 0x03; }
uint8_t unitType() { return _first & 0x1F; } uint8_t unitType() { return _first & 0x1F; }
@ -36,13 +40,12 @@ struct RTC_CPP_EXPORT NalUnitHeader {
void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); }
void setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); } void setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); }
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); } void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
private:
uint8_t _first = 0;
}; };
/// Nalu fragment header /// Nalu fragment header
struct RTC_CPP_EXPORT NalUnitFragmentHeader { struct RTC_CPP_EXPORT NalUnitFragmentHeader {
uint8_t _first = 0;
bool isStart() { return _first >> 7; } bool isStart() { return _first >> 7; }
bool reservedBit6() { return (_first >> 6) & 0x01; } bool reservedBit6() { return (_first >> 6) & 0x01; }
bool isEnd() { return (_first >> 5) & 0x01; } bool isEnd() { return (_first >> 5) & 0x01; }
@ -52,9 +55,6 @@ struct RTC_CPP_EXPORT NalUnitFragmentHeader {
void setEnd(bool isSet) { _first = (_first & 0xDF) | (isSet << 6); } void setEnd(bool isSet) { _first = (_first & 0xDF) | (isSet << 6); }
void setReservedBit6(bool isSet) { _first = (_first & 0xBF) | (isSet << 5); } void setReservedBit6(bool isSet) { _first = (_first & 0xBF) | (isSet << 5); }
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); } void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
private:
uint8_t _first = 0;
}; };
#pragma pack(pop) #pragma pack(pop)
@ -152,4 +152,4 @@ public:
#endif /* RTC_ENABLE_MEDIA */ #endif /* RTC_ENABLE_MEDIA */
#endif /* NAL_UNIT_H */ #endif /* RTC_NAL_UNIT_H */

View File

@ -1,19 +1,19 @@
/* /**
* libdatachannel client example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_OPUS_PACKETIZATION_HANDLER_H #ifndef RTC_OPUS_PACKETIZATION_HANDLER_H
@ -27,7 +27,7 @@
namespace rtc { namespace rtc {
/// Handler for opus packetization /// Handler for opus packetization
class RTC_CPP_EXPORT OpusPacketizationHandler : public MediaChainableHandler { class RTC_CPP_EXPORT OpusPacketizationHandler final : public MediaChainableHandler {
public: public:
/// Construct handler for opus packetization. /// Construct handler for opus packetization.

View File

@ -1,19 +1,19 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_OPUS_RTP_PACKETIZER_H #ifndef RTC_OPUS_RTP_PACKETIZER_H
@ -27,10 +27,10 @@
namespace rtc { namespace rtc {
/// RTP packetizer for opus /// RTP packetizer for opus
class RTC_CPP_EXPORT OpusRtpPacketizer : public RtpPacketizer, public MediaHandlerRootElement { class RTC_CPP_EXPORT OpusRtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement {
public: public:
/// default clock rate used in opus RTP communication /// default clock rate used in opus RTP communication
static const uint32_t defaultClockRate = 48 * 1000; inline static const uint32_t defaultClockRate = 48 * 1000;
/// Constructs opus packetizer with given RTP configuration. /// Constructs opus packetizer with given RTP configuration.
/// @note RTP configuration is used in packetization process which may change some configuration /// @note RTP configuration is used in packetization process which may change some configuration

View File

@ -24,7 +24,6 @@
#include "datachannel.hpp" #include "datachannel.hpp"
#include "description.hpp" #include "description.hpp"
#include "common.hpp" #include "common.hpp"
#include "init.hpp"
#include "message.hpp" #include "message.hpp"
#include "reliability.hpp" #include "reliability.hpp"
#include "track.hpp" #include "track.hpp"
@ -82,8 +81,6 @@ public:
State state() const; State state() const;
GatheringState gatheringState() const; GatheringState gatheringState() const;
SignalingState signalingState() const; SignalingState signalingState() const;
bool hasLocalDescription() const;
bool hasRemoteDescription() const;
bool hasMedia() const; bool hasMedia() const;
optional<Description> localDescription() const; optional<Description> localDescription() const;
optional<Description> remoteDescription() const; optional<Description> remoteDescription() const;

View File

@ -46,7 +46,8 @@ extern "C" {
#define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU #define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE ((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6 #define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE \
((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6
#define RTC_DEFAULT_MAXIMUM_PACKET_COUNT_FOR_NACK_CACHE ((unsigned)512) #define RTC_DEFAULT_MAXIMUM_PACKET_COUNT_FOR_NACK_CACHE ((unsigned)512)
#endif #endif
@ -94,61 +95,30 @@ typedef enum {
RTC_CERTIFICATE_RSA = 2, RTC_CERTIFICATE_RSA = 2,
} rtcCertificateType; } rtcCertificateType;
#if RTC_ENABLE_MEDIA
typedef enum { typedef enum {
// video // video
RTC_CODEC_H264 = 0, RTC_CODEC_H264 = 0,
RTC_CODEC_VP8 = 1, RTC_CODEC_VP8 = 1,
RTC_CODEC_VP9 = 2, RTC_CODEC_VP9 = 2,
// audio // audio
RTC_CODEC_OPUS = 128 RTC_CODEC_OPUS = 128
} rtcCodec; } rtcCodec;
typedef enum { typedef enum {
RTC_DIRECTION_UNKNOWN = 0, RTC_DIRECTION_UNKNOWN = 0,
RTC_DIRECTION_SENDONLY = 1, RTC_DIRECTION_SENDONLY = 1,
RTC_DIRECTION_RECVONLY = 2, RTC_DIRECTION_RECVONLY = 2,
RTC_DIRECTION_SENDRECV = 3, RTC_DIRECTION_SENDRECV = 3,
RTC_DIRECTION_INACTIVE = 4 RTC_DIRECTION_INACTIVE = 4
} rtcDirection; } rtcDirection;
#endif // RTC_ENABLE_MEDIA
#define RTC_ERR_SUCCESS 0 #define RTC_ERR_SUCCESS 0
#define RTC_ERR_INVALID -1 // invalid argument #define RTC_ERR_INVALID -1 // invalid argument
#define RTC_ERR_FAILURE -2 // runtime error #define RTC_ERR_FAILURE -2 // runtime error
#define RTC_ERR_NOT_AVAIL -3 // element not available #define RTC_ERR_NOT_AVAIL -3 // element not available
#define RTC_ERR_TOO_SMALL -4 // buffer too small #define RTC_ERR_TOO_SMALL -4 // buffer too small
typedef struct {
const char **iceServers;
int iceServersCount;
rtcCertificateType certificateType;
bool enableIceTcp;
bool disableAutoNegotiation;
uint16_t portRangeBegin;
uint16_t portRangeEnd;
int mtu; // <= 0 means automatic
int maxMessageSize; // <= 0 means default
} rtcConfiguration;
typedef struct {
bool unordered;
bool unreliable;
int maxPacketLifeTime; // ignored if reliable
int maxRetransmits; // ignored if reliable
} rtcReliability;
typedef struct {
rtcReliability reliability;
const char *protocol; // empty string if NULL
bool negotiated;
bool manualStream;
uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
} rtcDataChannelInit;
typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message); typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type, typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
void *ptr); void *ptr);
@ -167,14 +137,28 @@ typedef void(RTC_API *rtcBufferedAmountLowCallbackFunc)(int id, void *ptr);
typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr); typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
// Log // Log
// NULL cb on the first call will log to stdout // NULL cb on the first call will log to stdout
RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb); RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
// User pointer // User pointer
RTC_EXPORT void rtcSetUserPointer(int id, void *ptr); RTC_EXPORT void rtcSetUserPointer(int id, void *ptr);
RTC_EXPORT void * rtcGetUserPointer(int i); RTC_EXPORT void *rtcGetUserPointer(int i);
// PeerConnection // PeerConnection
typedef struct {
const char **iceServers;
int iceServersCount;
rtcCertificateType certificateType;
bool enableIceTcp;
bool disableAutoNegotiation;
uint16_t portRangeBegin;
uint16_t portRangeEnd;
int mtu; // <= 0 means automatic
int maxMessageSize; // <= 0 means default
} rtcConfiguration;
RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
RTC_EXPORT int rtcDeletePeerConnection(int pc); RTC_EXPORT int rtcDeletePeerConnection(int pc);
@ -201,6 +185,22 @@ RTC_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, c
int remoteSize); int remoteSize);
// DataChannel // DataChannel
typedef struct {
bool unordered;
bool unreliable;
int maxPacketLifeTime; // ignored if reliable
int maxRetransmits; // ignored if reliable
} rtcReliability;
typedef struct {
rtcReliability reliability;
const char *protocol; // empty string if NULL
bool negotiated;
bool manualStream;
uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
} rtcDataChannelInit;
RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb); RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label, RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
@ -213,108 +213,96 @@ RTC_EXPORT int rtcGetDataChannelProtocol(int dc, char *buffer, int size);
RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability); RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability);
// Track // Track
typedef struct {
rtcDirection direction;
rtcCodec codec;
int payloadType;
uint32_t ssrc;
const char *mid;
const char *name; // optional
const char *msid; // optional
const char *trackId; // optional, track ID used in MSID
} rtcTrackInit;
RTC_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb); RTC_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb);
RTC_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id RTC_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id
RTC_EXPORT int rtcAddTrackEx(int pc, const rtcTrackInit *init); // returns tr id
RTC_EXPORT int rtcDeleteTrack(int tr); RTC_EXPORT int rtcDeleteTrack(int tr);
RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size); RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
// Media
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
/// Add track // Media
/// @param pc Peer connection id
/// @param codec Codec
/// @param payloadType Payload type
/// @param ssrc SSRC
/// @param _mid MID
/// @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, const char *_trackID);
/// Set H264PacketizationHandler for track typedef struct {
/// @param tr Track id uint32_t ssrc;
/// @param ssrc SSRC const char *cname;
/// @param cname CName uint8_t payloadType;
/// @param payloadType Payload Type uint32_t clockRate;
/// @param clockRate Clock rate uint16_t maxFragmentSize; // Maximum NALU fragment size
/// @param maxFragmentSize Maximum NALU fragment size uint16_t sequenceNumber;
/// @param sequenceNumber Sequence number uint32_t timestamp;
/// @param timestamp Timestamp } rtcPacketizationHandlerInit;
RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char * cname, uint8_t payloadType, uint32_t clockRate, uint16_t maxFragmentSize, uint16_t sequenceNumber, uint32_t timestamp);
/// Set OpusPacketizationHandler for track typedef struct {
/// @param tr Track id double seconds; // Start time in seconds
/// @param ssrc SSRC bool since1970; // true if seconds since 1970
/// @param cname CName // false if seconds since 1900
/// @param payloadType Payload Type uint32_t timestamp; // Start timestamp
/// @param clockRate Clock rate } rtcStartTime;
/// @param _sequenceNumber Sequence number
/// @param _timestamp Timestamp
RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char * cname, uint8_t payloadType, uint32_t clockRate, uint16_t _sequenceNumber, uint32_t _timestamp);
/// Chain RtcpSrReporter to handler chain for given track // Set H264PacketizationHandler for track
/// @param tr Track id RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
int rtcChainRtcpSrReporter(int tr);
/// Chain RtcpNackResponder to handler chain for given track // Set OpusPacketizationHandler for track
/// @param tr Track id RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
/// @param maxStoredPacketsCount Maximum stored packet count
int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount); // Chain RtcpSrReporter to handler chain for given track
RTC_EXPORT int rtcChainRtcpSrReporter(int tr);
// Chain RtcpNackResponder to handler chain for given track
RTC_EXPORT int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount);
/// Set start time for RTP stream /// Set start time for RTP stream
/// @param startTime_s Start time in seconds RTC_EXPORT int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime);
/// @param timeIntervalSince1970 Set true if `startTime_s` is time interval since 1970, false if `startTime_s` is time interval since 1900
/// @param _timestamp Start timestamp
int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970, uint32_t _timestamp);
/// Start stats recording for RTCP Sender Reporter // Start stats recording for RTCP Sender Reporter
/// @param id Track identifier RTC_EXPORT int rtcStartRtcpSenderReporterRecording(int id);
int rtcStartRtcpSenderReporterRecording(int id);
/// Transform seconds to timestamp using track's clock rate // Transform seconds to timestamp using track's clock rate
/// @param id Track id // Result is written to timestamp
/// @param seconds Seconds RTC_EXPORT int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
/// @param timestamp Pointer to result
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t * timestamp);
/// Transform timestamp to seconds using track's clock rate // Transform timestamp to seconds using track's clock rate
/// @param id Track id // Result is written to seconds
/// @param timestamp Timestamp RTC_EXPORT int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds);
/// @param seconds Pointer for result
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double * seconds);
/// Get current timestamp // Get current timestamp
/// @param id Track id // Result is written to timestamp
/// @param timestamp Pointer for result RTC_EXPORT int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp);
int rtcGetCurrentTrackTimestamp(int id, uint32_t * timestamp);
/// Get start timestamp for track identified by given id // Get start timestamp for track identified by given id
/// @param id Track id // Result is written to timestamp
/// @param timestamp Pointer for result RTC_EXPORT int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp);
int rtcGetTrackStartTimestamp(int id, uint32_t * timestamp);
/// Set RTP timestamp for track identified by given id // Set RTP timestamp for track identified by given id
/// @param id Track id RTC_EXPORT int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp);
/// @param timestamp New timestamp
int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp);
/// Get timestamp of previous RTCP SR // Get timestamp of previous RTCP SR
/// @param id Track id // Result is written to timestamp
/// @param timestamp Pointer for result RTC_EXPORT int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp);
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t * timestamp);
/// Set `NeedsToReport` flag in RtcpSrReporter handler identified by given track id // Set NeedsToReport flag in RtcpSrReporter handler identified by given track id
/// @param id Track id RTC_EXPORT int rtcSetNeedsToSendRtcpSr(int id);
int rtcSetNeedsToSendRtcpSr(int id);
#endif // RTC_ENABLE_MEDIA #endif // RTC_ENABLE_MEDIA
// WebSocket
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
// WebSocket
typedef struct { typedef struct {
bool disableTlsVerification; // if true, don't verify the TLS certificate bool disableTlsVerification; // if true, don't verify the TLS certificate
} rtcWsConfiguration; } rtcWsConfiguration;
@ -322,9 +310,11 @@ typedef struct {
RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id
RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config); RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config);
RTC_EXPORT int rtcDeleteWebsocket(int ws); RTC_EXPORT int rtcDeleteWebsocket(int ws);
#endif #endif
// DataChannel, Track, and WebSocket common API // DataChannel, Track, and WebSocket common API
RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb); RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb);
RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb); RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb);
RTC_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb); RTC_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb);
@ -336,14 +326,31 @@ RTC_EXPORT int rtcSetBufferedAmountLowThreshold(int id, int amount);
RTC_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb); RTC_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb);
// DataChannel, Track, and WebSocket common extended API // DataChannel, Track, and WebSocket common extended API
RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive
RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb); RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb);
RTC_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size); RTC_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size);
// Optional preload and cleanup // Optional global preload and cleanup
RTC_EXPORT void rtcPreload(void); RTC_EXPORT void rtcPreload(void);
RTC_EXPORT void rtcCleanup(void); RTC_EXPORT void rtcCleanup(void);
// SCTP global settings
typedef struct {
int recvBufferSize; // in bytes, <= 0 means optimized default
int sendBufferSize; // in bytes, <= 0 means optimized default
int maxChunksOnQueue; // in chunks, <= 0 means optimized default
int initialCongestionWindow; // in MTUs, <= 0 means optimized default
int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled
int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC
int delayedSackTimeMs; // in msecs, <= 0 means optimized default
} rtcSctpSettings;
// Note: SCTP settings apply to newly-created PeerConnections only
RTC_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -21,12 +21,11 @@
// C++ API // C++ API
#include "common.hpp" #include "common.hpp"
#include "init.hpp" // for rtc::Cleanup() #include "global.hpp"
#include "log.hpp"
// //
#include "datachannel.hpp" #include "datachannel.hpp"
#include "track.hpp"
#include "peerconnection.hpp" #include "peerconnection.hpp"
#include "track.hpp"
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
@ -38,14 +37,13 @@
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
// Media handling // Media handling
#include "rtcpreceivingsession.hpp"
#include "mediachainablehandler.hpp" #include "mediachainablehandler.hpp"
#include "rtcpsrreporter.hpp"
#include "rtcpnackresponder.hpp" #include "rtcpnackresponder.hpp"
#include "rtcpreceivingsession.hpp"
#include "rtcpsrreporter.hpp"
// Opus/h264 streaming // Opus/h264 streaming
#include "h264packetizationhandler.hpp" #include "h264packetizationhandler.hpp"
#include "opuspacketizationhandler.hpp" #include "opuspacketizationhandler.hpp"
#endif // RTC_ENABLE_MEDIA #endif // RTC_ENABLE_MEDIA

View File

@ -1,18 +1,19 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_RTCP_NACK_RESPONDER_H #ifndef RTC_RTCP_NACK_RESPONDER_H
@ -27,11 +28,11 @@
namespace rtc { namespace rtc {
class RTC_CPP_EXPORT RtcpNackResponder: public MediaHandlerElement { class RTC_CPP_EXPORT RtcpNackResponder final: public MediaHandlerElement {
/// Packet storage /// Packet storage
class RTC_CPP_EXPORT Storage { class RTC_CPP_EXPORT Storage {
/// Packet storage element /// Packet storage element
struct RTC_CPP_EXPORT Element { struct RTC_CPP_EXPORT Element {
Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next = nullptr); Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next = nullptr);

View File

@ -1,18 +1,19 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_RTCP_SENDER_REPORTABLE_H #ifndef RTC_RTCP_SENDER_REPORTABLE_H
@ -26,7 +27,7 @@
namespace rtc { namespace rtc {
class RTC_CPP_EXPORT RtcpSrReporter: public MediaHandlerElement { class RTC_CPP_EXPORT RtcpSrReporter final: public MediaHandlerElement {
bool needsToReport = false; bool needsToReport = false;

View File

@ -21,23 +21,9 @@
#ifndef RTC_RTP_HPP #ifndef RTC_RTP_HPP
#define RTC_RTP_HPP #define RTC_RTP_HPP
#include "log.hpp" #include "common.hpp"
#include <cmath> #include <vector>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#ifndef htonll
#define htonll(x) \
((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32)))
#endif
#ifndef ntohll
#define ntohll(x) htonll(x)
#endif
namespace rtc { namespace rtc {
@ -45,63 +31,40 @@ typedef uint32_t SSRC;
#pragma pack(push, 1) #pragma pack(push, 1)
struct RTP { struct RTC_CPP_EXPORT RTP {
private:
uint8_t _first; uint8_t _first;
uint8_t _payloadType; uint8_t _payloadType;
uint16_t _seqNumber; uint16_t _seqNumber;
uint32_t _timestamp; uint32_t _timestamp;
SSRC _ssrc; SSRC _ssrc;
SSRC _csrc[16];
public: [[nodiscard]] uint8_t version() const;
SSRC csrc[16]; [[nodiscard]] bool padding() const;
[[nodiscard]] bool extension() const;
[[nodiscard]] uint8_t csrcCount() const;
[[nodiscard]] uint8_t marker() const;
[[nodiscard]] uint8_t payloadType() const;
[[nodiscard]] uint16_t seqNumber() const;
[[nodiscard]] uint32_t timestamp() const;
[[nodiscard]] uint32_t ssrc() const;
inline uint8_t version() const { return _first >> 6; } [[nodiscard]] size_t getSize() const;
inline bool padding() const { return (_first >> 5) & 0x01; } [[nodiscard]] const char *getBody() const;
inline bool extension() const { return (_first >> 4) & 0x01; } [[nodiscard]] char *getBody();
inline uint8_t csrcCount() const { return _first & 0x0F; }
inline uint8_t marker() const { return _payloadType & 0b10000000; }
inline uint8_t payloadType() const { return _payloadType & 0b01111111; }
inline uint16_t seqNumber() const { return ntohs(_seqNumber); }
inline uint32_t timestamp() const { return ntohl(_timestamp); }
inline uint32_t ssrc() const { return ntohl(_ssrc); }
inline size_t getSize() const { void log() const;
return reinterpret_cast<const char *>(&csrc) - reinterpret_cast<const char *>(this) +
sizeof(SSRC) * csrcCount();
}
[[nodiscard]] char *getBody() { void preparePacket();
return reinterpret_cast<char *>(&csrc) + sizeof(SSRC) * csrcCount(); void setSeqNumber(uint16_t newSeqNo);
} void setPayloadType(uint8_t newPayloadType);
void setSsrc(uint32_t in_ssrc);
[[nodiscard]] const char *getBody() const { void setMarker(bool marker);
return reinterpret_cast<const char *>(&csrc) + sizeof(SSRC) * csrcCount(); void setTimestamp(uint32_t i);
}
inline void preparePacket() { _first |= (1 << 7); }
inline void setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); }
inline void setPayloadType(uint8_t newPayloadType) {
_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
}
inline void setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); }
inline void setMarker(bool marker) { _payloadType = (_payloadType & 0x7F) | (marker << 7); };
void setTimestamp(uint32_t i) { _timestamp = htonl(i); }
void log() {
PLOG_VERBOSE << "RTP V: " << (int)version() << " P: " << (padding() ? "P" : " ")
<< " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount()
<< " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType()
<< " SEQNO: " << seqNumber() << " TS: " << timestamp();
}
}; };
struct RTCP_ReportBlock { struct RTC_CPP_EXPORT RTCP_ReportBlock {
SSRC ssrc; SSRC _ssrc;
private:
uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit
uint16_t _seqNoCycles; uint16_t _seqNoCycles;
uint16_t _highestSeqNo; uint16_t _highestSeqNo;
@ -109,136 +72,68 @@ private:
uint32_t _lastReport; uint32_t _lastReport;
uint32_t _delaySinceLastReport; uint32_t _delaySinceLastReport;
public: [[nodiscard]] uint16_t seqNoCycles() const;
inline void preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost, [[nodiscard]] uint16_t highestSeqNo() const;
[[maybe_unused]] unsigned int totalPackets, uint16_t highestSeqNo, [[nodiscard]] uint32_t jitter() const;
uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP, [[nodiscard]] uint32_t delaySinceSR() const;
uint64_t lastSR_DELAY) {
setSeqNo(highestSeqNo, seqNoCycles);
setJitter(jitter);
setSSRC(in_ssrc);
// Middle 32 bits of NTP Timestamp [[nodiscard]] SSRC getSSRC() const;
// this->lastReport = lastSR_NTP >> 16u; [[nodiscard]] uint32_t getNTPOfSR() const;
setNTPOfSR(uint64_t(lastSR_NTP)); [[nodiscard]] unsigned int getLossPercentage() const;
setDelaySinceSR(uint32_t(lastSR_DELAY)); [[nodiscard]] unsigned int getPacketLostCount() const;
// The delay, expressed in units of 1/65536 seconds void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets,
// this->delaySinceLastReport = lastSR_DELAY; uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter,
} uint64_t lastSR_NTP, uint64_t lastSR_DELAY);
void setSSRC(SSRC in_ssrc);
void setPacketsLost(unsigned int packetsLost, unsigned int totalPackets);
void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles);
void setJitter(uint32_t jitter);
void setNTPOfSR(uint64_t ntp);
void setDelaySinceSR(uint32_t sr);
inline void setSSRC(SSRC in_ssrc) { this->ssrc = htonl(in_ssrc); } void log() const;
[[nodiscard]] inline SSRC getSSRC() const { return ntohl(ssrc); }
inline void setPacketsLost([[maybe_unused]] unsigned int packetsLost,
[[maybe_unused]] unsigned int totalPackets) {
// TODO Implement loss percentages.
_fractionLostAndPacketsLost = 0;
}
[[nodiscard]] inline unsigned int getLossPercentage() const {
// TODO Implement loss percentages.
return 0;
}
[[nodiscard]] inline unsigned int getPacketLostCount() const {
// TODO Implement total packets lost.
return 0;
}
inline uint16_t seqNoCycles() const { return ntohs(_seqNoCycles); }
inline uint16_t highestSeqNo() const { return ntohs(_highestSeqNo); }
inline uint32_t jitter() const { return ntohl(_jitter); }
inline void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) {
_highestSeqNo = htons(highestSeqNo);
_seqNoCycles = htons(seqNoCycles);
}
inline void setJitter(uint32_t jitter) { _jitter = htonl(jitter); }
inline void setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); }
[[nodiscard]] inline uint32_t getNTPOfSR() const { return ntohl(_lastReport) << 16u; }
inline void setDelaySinceSR(uint32_t sr) {
// The delay, expressed in units of 1/65536 seconds
_delaySinceLastReport = htonl(sr);
}
[[nodiscard]] inline uint32_t getDelaySinceSR() const { return ntohl(_delaySinceLastReport); }
inline void log() const {
PLOG_VERBOSE << "RTCP report block: "
<< "ssrc="
<< ntohl(ssrc)
// TODO: Implement these reports
// << ", fractionLost=" << fractionLost
// << ", packetsLost=" << packetsLost
<< ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles()
<< ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR()
<< ", lastSRDelay=" << getDelaySinceSR();
}
}; };
struct RTCP_HEADER { struct RTC_CPP_EXPORT RTCP_HEADER {
private:
uint8_t _first; uint8_t _first;
uint8_t _payloadType; uint8_t _payloadType;
uint16_t _length; uint16_t _length;
public: [[nodiscard]] uint8_t version() const;
inline uint8_t version() const { return _first >> 6; } [[nodiscard]] bool padding() const;
inline bool padding() const { return (_first >> 5) & 0x01; } [[nodiscard]] uint8_t reportCount() const;
inline uint8_t reportCount() const { return _first & 0x0F; } [[nodiscard]] uint8_t payloadType() const;
inline uint8_t payloadType() const { return _payloadType; } [[nodiscard]] uint16_t length() const;
inline uint16_t length() const { return ntohs(_length); } [[nodiscard]] size_t lengthInBytes() const;
inline size_t lengthInBytes() const { return (1 + length()) * 4; }
inline void setPayloadType(uint8_t type) { _payloadType = type; } void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length);
inline void setReportCount(uint8_t count) { void setPayloadType(uint8_t type);
_first = (_first & 0b11100000u) | (count & 0b00011111u); void setReportCount(uint8_t count);
} void setLength(uint16_t length);
inline void setLength(uint16_t length) { _length = htons(length); }
inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) { void log() const;
_first = 0b10000000; // version 2, no padding
setReportCount(reportCount);
setPayloadType(payloadType);
setLength(length);
}
inline void log() const {
PLOG_VERBOSE << "RTCP header: "
<< "version=" << unsigned(version()) << ", padding=" << padding()
<< ", reportCount=" << unsigned(reportCount())
<< ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
}
}; };
struct RTCP_FB_HEADER { struct RTC_CPP_EXPORT RTCP_FB_HEADER {
RTCP_HEADER header; RTCP_HEADER header;
SSRC packetSender;
SSRC mediaSource;
[[nodiscard]] SSRC getPacketSenderSSRC() const { return ntohl(packetSender); } SSRC _packetSender;
SSRC _mediaSource;
[[nodiscard]] SSRC getMediaSourceSSRC() const { return ntohl(mediaSource); } [[nodiscard]] SSRC packetSenderSSRC() const;
[[nodiscard]] SSRC mediaSourceSSRC() const;
void setPacketSenderSSRC(SSRC ssrc) { this->packetSender = htonl(ssrc); } void setPacketSenderSSRC(SSRC ssrc);
void setMediaSourceSSRC(SSRC ssrc);
void setMediaSourceSSRC(SSRC ssrc) { this->mediaSource = htonl(ssrc); } void log() const;
void log() {
header.log();
PLOG_VERBOSE << "FB: "
<< " packet sender: " << getPacketSenderSSRC()
<< " media source: " << getMediaSourceSSRC();
}
}; };
struct RTCP_SR { struct RTC_CPP_EXPORT RTCP_SR {
RTCP_HEADER header; RTCP_HEADER header;
SSRC _senderSSRC; SSRC _senderSSRC;
private:
uint64_t _ntpTimestamp; uint64_t _ntpTimestamp;
uint32_t _rtpTimestamp; uint32_t _rtpTimestamp;
uint32_t _packetCount; uint32_t _packetCount;
@ -246,418 +141,175 @@ private:
RTCP_ReportBlock _reportBlocks; RTCP_ReportBlock _reportBlocks;
public: [[nodiscard]] static unsigned int Size(unsigned int reportCount);
inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) {
unsigned int length =
((sizeof(header) + 24 + reportCount * sizeof(RTCP_ReportBlock)) / 4) - 1;
header.prepareHeader(200, reportCount, uint16_t(length));
this->_senderSSRC = htonl(senderSSRC);
}
[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; } [[nodiscard]] uint64_t ntpTimestamp() const;
[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const { [[nodiscard]] uint32_t rtpTimestamp() const;
return &_reportBlocks + num; [[nodiscard]] uint32_t packetCount() const;
} [[nodiscard]] uint32_t octetCount() const;
[[nodiscard]] uint32_t senderSSRC() const;
[[nodiscard]] static unsigned int size(unsigned int reportCount) { [[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock); [[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
} [[nodiscard]] unsigned int size(unsigned int reportCount);
[[nodiscard]] size_t getSize() const;
[[nodiscard]] inline size_t getSize() const { void preparePacket(SSRC senderSSRC, uint8_t reportCount);
// "length" in packet is one less than the number of 32 bit words in the packet. void setNtpTimestamp(uint64_t ts);
return sizeof(uint32_t) * (1 + size_t(header.length())); void setRtpTimestamp(uint32_t ts);
} void setOctetCount(uint32_t ts);
void setPacketCount(uint32_t ts);
inline uint64_t ntpTimestamp() const { return ntohll(_ntpTimestamp); } void log() const;
inline uint32_t rtpTimestamp() const { return ntohl(_rtpTimestamp); }
inline uint32_t packetCount() const { return ntohl(_packetCount); }
inline uint32_t octetCount() const { return ntohl(_octetCount); }
inline uint32_t senderSSRC() const { return ntohl(_senderSSRC); }
inline void setNtpTimestamp(uint64_t ts) { _ntpTimestamp = htonll(ts); }
inline void setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); }
inline void setOctetCount(uint32_t ts) { _octetCount = htonl(ts); }
inline void setPacketCount(uint32_t ts) { _packetCount = htonl(ts); }
inline void log() const {
header.log();
PLOG_VERBOSE << "RTCP SR: "
<< " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp()
<< ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount()
<< ", octetCount=" << octetCount();
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
getReportBlock(i)->log();
}
}
}; };
struct RTCP_SDES_ITEM { struct RTC_CPP_EXPORT RTCP_SDES_ITEM {
public:
uint8_t type; uint8_t type;
private:
uint8_t _length; uint8_t _length;
char _text[1]; char _text[1];
public: [[nodiscard]] static unsigned int Size(uint8_t textLength);
inline std::string text() const { return std::string(_text, _length); }
inline void setText(std::string text) {
if(text.size() > 0xFF)
throw std::invalid_argument("text is too long");
_length = uint8_t(text.size()); [[nodiscard]] string text() const;
memcpy(_text, text.data(), text.size()); [[nodiscard]] uint8_t length() const;
}
inline uint8_t length() { return _length; } void setText(string text);
[[nodiscard]] static unsigned int size(uint8_t textLength) { return textLength + 2; }
}; };
struct RTCP_SDES_CHUNK { struct RTCP_SDES_CHUNK {
private:
SSRC _ssrc; SSRC _ssrc;
RTCP_SDES_ITEM _items; RTCP_SDES_ITEM _items;
public: [[nodiscard]] static unsigned int Size(const std::vector<uint8_t> textLengths);
inline SSRC ssrc() const { return ntohl(_ssrc); }
inline void setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); }
/// Get item at given index [[nodiscard]] SSRC ssrc() const;
/// @note All items with index < `num` must be valid, otherwise this function has undefined
/// behaviour (use `safelyCountChunkSize` to check if chunk is valid)
/// @param num Index of item to return
inline RTCP_SDES_ITEM *getItem(int num) {
auto base = &_items;
while (num-- > 0) {
auto itemSize = RTCP_SDES_ITEM::size(base->length());
base = reinterpret_cast<RTCP_SDES_ITEM *>(reinterpret_cast<uint8_t *>(base) + itemSize);
}
return reinterpret_cast<RTCP_SDES_ITEM *>(base);
}
long safelyCountChunkSize(size_t maxChunkSize) { void setSSRC(SSRC ssrc);
if (maxChunkSize < RTCP_SDES_CHUNK::size({})) {
// chunk is truncated
return -1;
} else {
size_t size = sizeof(SSRC);
unsigned int i = 0;
// We can always access first 4 bytes of first item (in case of no items there will be 4
// null bytes)
auto item = getItem(i);
std::vector<uint8_t> textsLength{};
while (item->type != 0) {
if (size + RTCP_SDES_ITEM::size(0) > maxChunkSize) {
// item is too short
return -1;
}
auto itemLength = item->length();
if (size + RTCP_SDES_ITEM::size(itemLength) >= maxChunkSize) {
// item is too large (it can't be equal to chunk size because after item there
// must be 1-4 null bytes as padding)
return -1;
}
textsLength.push_back(itemLength);
// safely to access next item
item = getItem(++i);
}
auto realSize = RTCP_SDES_CHUNK::size(textsLength);
if (realSize > maxChunkSize) {
// Chunk is too large
return -1;
}
return realSize;
}
}
[[nodiscard]] static unsigned int size(const std::vector<uint8_t> textLengths) { // Get item at given index
unsigned int itemsSize = 0; // All items with index < num must be valid, otherwise this function has undefined behaviour
for (auto length : textLengths) { // (use safelyCountChunkSize() to check if chunk is valid).
itemsSize += RTCP_SDES_ITEM::size(length); [[nodiscard]] const RTCP_SDES_ITEM *getItem(int num) const;
} [[nodiscard]] RTCP_SDES_ITEM *getItem(int num);
auto nullTerminatedItemsSize = itemsSize + 1;
auto words = uint8_t(std::ceil(double(nullTerminatedItemsSize) / 4)) + 1;
return words * 4;
}
/// Get size of chunk // Get size of chunk
/// @note All items must be valid, otherwise this function has undefined behaviour (use // All items must be valid, otherwise this function has undefined behaviour (use
/// `safelyCountChunkSize` to check if chunk is valid) // safelyCountChunkSize() to check if chunk is valid)
[[nodiscard]] unsigned int getSize() { [[nodiscard]] unsigned int getSize() const;
std::vector<uint8_t> textLengths{};
unsigned int i = 0; long safelyCountChunkSize(size_t maxChunkSize) const;
auto item = getItem(i);
while (item->type != 0) {
textLengths.push_back(item->length());
item = getItem(++i);
}
return size(textLengths);
}
}; };
struct RTCP_SDES { struct RTC_CPP_EXPORT RTCP_SDES {
RTCP_HEADER header; RTCP_HEADER header;
private:
RTCP_SDES_CHUNK _chunks; RTCP_SDES_CHUNK _chunks;
public: [[nodiscard]] static unsigned int Size(const std::vector<std::vector<uint8_t>> lengths);
inline void preparePacket(uint8_t chunkCount) {
unsigned int chunkSize = 0;
for (uint8_t i = 0; i < chunkCount; i++) {
auto chunk = getChunk(i);
chunkSize += chunk->getSize();
}
uint16_t length = uint16_t((sizeof(header) + chunkSize) / 4 - 1);
header.prepareHeader(202, chunkCount, length);
}
bool isValid() { bool isValid() const;
auto chunksSize = header.lengthInBytes() - sizeof(header);
if (chunksSize == 0) {
return true;
} else {
// there is at least one chunk
unsigned int i = 0;
unsigned int size = 0;
while (size < chunksSize) {
if (chunksSize < size + RTCP_SDES_CHUNK::size({})) {
// chunk is truncated
return false;
}
auto chunk = getChunk(i++);
auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size);
if (chunkSize < 0) {
// chunk is invalid
return false;
}
size += chunkSize;
}
return size == chunksSize;
}
}
/// Returns number of chunks in this packet // Returns number of chunks in this packet
/// @note Returns 0 if packet is invalid // Returns 0 if packet is invalid
inline unsigned int chunksCount() { unsigned int chunksCount() const;
if (!isValid()) {
return 0;
}
uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header);
unsigned int size = 0;
unsigned int i = 0;
while (size < chunksSize) {
size += getChunk(i++)->getSize();
}
return i;
}
/// Get chunk at given index // Get chunk at given index
/// @note All chunks (and their items) with index < `num` must be valid, otherwise this function // All chunks (and their items) with index < `num` must be valid, otherwise this function has
/// has undefined behaviour (use `isValid` to check if chunk is valid) // undefined behaviour (use `isValid` to check if chunk is valid).
/// @param num Index of chunk to return const RTCP_SDES_CHUNK *getChunk(int num) const;
inline RTCP_SDES_CHUNK *getChunk(int num) { RTCP_SDES_CHUNK *getChunk(int num);
auto base = &_chunks;
while (num-- > 0) {
auto chunkSize = base->getSize();
base =
reinterpret_cast<RTCP_SDES_CHUNK *>(reinterpret_cast<uint8_t *>(base) + chunkSize);
}
return reinterpret_cast<RTCP_SDES_CHUNK *>(base);
}
[[nodiscard]] static unsigned int size(const std::vector<std::vector<uint8_t>> lengths) { void preparePacket(uint8_t chunkCount);
unsigned int chunks_size = 0;
for (auto length : lengths) {
chunks_size += RTCP_SDES_CHUNK::size(length);
}
return 4 + chunks_size;
}
}; };
struct RTCP_RR { struct RTC_CPP_EXPORT RTCP_RR {
RTCP_HEADER header; RTCP_HEADER header;
SSRC _senderSSRC;
private: SSRC _senderSSRC;
RTCP_ReportBlock _reportBlocks; RTCP_ReportBlock _reportBlocks;
public: [[nodiscard]] static size_t SizeWithReportBlocks(uint8_t reportCount);
[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
return &_reportBlocks + num;
}
inline SSRC senderSSRC() const { return ntohl(_senderSSRC); } SSRC senderSSRC() const;
inline void setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); } bool isSenderReport();
bool isReceiverReport();
[[nodiscard]] inline size_t getSize() const { [[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
// "length" in packet is one less than the number of 32 bit words in the packet. [[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
return sizeof(uint32_t) * (1 + size_t(header.length())); [[nodiscard]] size_t getSize() const;
}
inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) { void preparePacket(SSRC senderSSRC, uint8_t reportCount);
// "length" in packet is one less than the number of 32 bit words in the packet. void setSenderSSRC(SSRC ssrc);
size_t length = (sizeWithReportBlocks(reportCount) / 4) - 1;
header.prepareHeader(201, reportCount, uint16_t(length));
this->_senderSSRC = htonl(senderSSRC);
}
inline static size_t sizeWithReportBlocks(uint8_t reportCount) { void log() const;
return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock);
}
inline bool isSenderReport() { return header.payloadType() == 200; }
inline bool isReceiverReport() { return header.payloadType() == 201; }
inline void log() const {
header.log();
PLOG_VERBOSE << "RTCP RR: "
<< " SSRC=" << ntohl(_senderSSRC);
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
getReportBlock(i)->log();
}
}
}; };
struct RTCP_REMB { struct RTC_CPP_EXPORT RTCP_REMB {
RTCP_FB_HEADER header; RTCP_FB_HEADER header;
/*! \brief Unique identifier ('R' 'E' 'M' 'B') */ char _id[4]; // Unique identifier ('R' 'E' 'M' 'B')
char id[4]; uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask)
SSRC _ssrc[1];
/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */ [[nodiscard]] static size_t SizeWithSSRCs(int count);
uint32_t bitrate;
SSRC ssrc[1]; [[nodiscard]] unsigned int getSize() const;
[[nodiscard]] unsigned int getSize() const { void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate);
// "length" in packet is one less than the number of 32 bit words in the packet. void setBitrate(unsigned int numSSRC, unsigned int in_bitrate);
return sizeof(uint32_t) * (1 + header.header.length()); void setSsrc(int iterator, SSRC newSssrc);
}
void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) {
// Report Count becomes the format here.
header.header.prepareHeader(206, 15, 0);
// Always zero.
header.setMediaSourceSSRC(0);
header.setPacketSenderSSRC(senderSSRC);
id[0] = 'R';
id[1] = 'E';
id[2] = 'M';
id[3] = 'B';
setBitrate(numSSRC, in_bitrate);
}
void setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
unsigned int exp = 0;
while (in_bitrate > pow(2, 18) - 1) {
exp++;
in_bitrate /= 2;
}
// "length" in packet is one less than the number of 32 bit words in the packet.
header.header.setLength(
uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate);
}
void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); }
size_t static inline sizeWithSSRCs(int count) {
return sizeof(RTCP_REMB) + (count - 1) * sizeof(SSRC);
}
}; };
struct RTCP_PLI { struct RTC_CPP_EXPORT RTCP_PLI {
RTCP_FB_HEADER header; RTCP_FB_HEADER header;
void preparePacket(SSRC messageSSRC) { [[nodiscard]] static unsigned int Size();
header.header.prepareHeader(206, 1, 2);
header.setPacketSenderSSRC(messageSSRC);
header.setMediaSourceSSRC(messageSSRC);
}
void print() { header.log(); } void preparePacket(SSRC messageSSRC);
[[nodiscard]] static unsigned int size() { return sizeof(RTCP_FB_HEADER); } void log() const;
}; };
struct RTCP_FIR_PART { struct RTC_CPP_EXPORT RTCP_FIR_PART {
uint32_t ssrc; uint32_t ssrc;
uint8_t seqNo; uint8_t seqNo;
uint8_t dummy1; uint8_t dummy1;
uint16_t dummy2; uint16_t dummy2;
}; };
struct RTCP_FIR { struct RTC_CPP_EXPORT RTCP_FIR {
RTCP_FB_HEADER header; RTCP_FB_HEADER header;
RTCP_FIR_PART parts[1]; RTCP_FIR_PART parts[1];
void preparePacket(SSRC messageSSRC, uint8_t seqNo) { static unsigned int Size();
header.header.prepareHeader(206, 4, 2 + 2 * 1);
header.setPacketSenderSSRC(messageSSRC);
header.setMediaSourceSSRC(messageSSRC);
parts[0].ssrc = htonl(messageSSRC);
parts[0].seqNo = seqNo;
}
void print() { header.log(); } void preparePacket(SSRC messageSSRC, uint8_t seqNo);
[[nodiscard]] static unsigned int size() { void log() const;
return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART);
}
}; };
struct RTCP_NACK_PART { struct RTC_CPP_EXPORT RTCP_NACK_PART {
uint16_t _pid; uint16_t _pid;
uint16_t _blp; uint16_t _blp;
uint16_t getPID() { return ntohs(_pid); } uint16_t pid();
uint16_t getBLP() { return ntohs(_blp); } uint16_t blp();
void setPID(uint16_t pid) { _pid = htons(pid); } void setPid(uint16_t pid);
void setBLP(uint16_t blp) { _blp = htons(blp); } void setBlp(uint16_t blp);
std::vector<uint16_t> getSequenceNumbers() { std::vector<uint16_t> getSequenceNumbers();
std::vector<uint16_t> result{};
result.reserve(17);
uint16_t pid = getPID();
result.push_back(pid);
uint16_t bitmask = getBLP();
uint16_t i = pid + 1;
while (bitmask > 0) {
if (bitmask & 0x1) {
result.push_back(i);
}
i += 1;
bitmask >>= 1;
}
return result;
}
}; };
class RTCP_NACK { struct RTC_CPP_EXPORT RTCP_NACK {
public:
RTCP_FB_HEADER header; RTCP_FB_HEADER header;
RTCP_NACK_PART parts[1]; RTCP_NACK_PART parts[1];
public: [[nodiscard]] static unsigned int Size(unsigned int discreteSeqNoCount);
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount)); [[nodiscard]] unsigned int getSeqNoCount();
header.setMediaSourceSSRC(ssrc);
header.setPacketSenderSSRC(ssrc); void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount);
}
/** /**
* Add a packet to the list of missing packets. * Add a packet to the list of missing packets.
@ -668,71 +320,22 @@ public:
* @param missingPacket The seq no of the missing packet. This will be added to the queue. * @param missingPacket The seq no of the missing packet. This will be added to the queue.
* @return true if the packet has grown, false otherwise. * @return true if the packet has grown, false otherwise.
*/ */
bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket) { bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket);
if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) {
parts[*fciCount].setPID(missingPacket);
parts[*fciCount].setBLP(0);
*fciPID = missingPacket;
(*fciCount)++;
return true;
} else {
// TODO SPEED!
uint16_t blp = parts[(*fciCount) - 1].getBLP();
uint16_t newBit = uint16_t(1u << (missingPacket - (1 + *fciPID)));
parts[(*fciCount) - 1].setBLP(blp | newBit);
return false;
}
}
[[nodiscard]] static unsigned int getSize(unsigned int discreteSeqNoCount) {
return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount;
}
[[nodiscard]] unsigned int getSeqNoCount() { return header.header.length() - 2; }
}; };
class RTP_RTX { struct RTC_CPP_EXPORT RTP_RTX {
private:
RTP header; RTP header;
public: [[nodiscard]] const char *getBody() const;
size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) { [[nodiscard]] char *getBody();
memmove((char *)dest, (char *)this, header.getSize()); [[nodiscard]] size_t getBodySize(size_t totalSize) const;
dest->setSeqNumber(getOriginalSeqNo()); [[nodiscard]] size_t getSize() const;
dest->setPayloadType(originalPayloadType); [[nodiscard]] uint16_t getOriginalSeqNo() const;
memmove(dest->getBody(), getBody(), getBodySize(totalSize));
return totalSize;
}
[[nodiscard]] uint16_t getOriginalSeqNo() const { // Returns the new size of the packet
return ntohs(*(uint16_t *)(header.getBody())); size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType);
}
[[nodiscard]] char *getBody() { return header.getBody() + sizeof(uint16_t); } size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType);
[[nodiscard]] const char *getBody() const { return header.getBody() + sizeof(uint16_t); }
[[nodiscard]] size_t getBodySize(size_t totalSize) {
return totalSize - (getBody() - reinterpret_cast<char *>(this));
}
[[nodiscard]] size_t getSize() const{
return header.getSize() + sizeof(uint16_t);
}
[[nodiscard]] RTP &getHeader() { return header; }
/*
* Returns the new size of the packet
*/
size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) {
header.setSeqNumber(getOriginalSeqNo());
header.setSsrc(originalSSRC);
header.setPayloadType(originalPayloadType);
// TODO, the -12 is the size of the header (which is variable!)
memmove(header.getBody(), getBody(), totalSize - getSize());
return totalSize - 2;
}
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -1,19 +1,19 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_RTP_PACKETIZATION_CONFIG_H #ifndef RTC_RTP_PACKETIZATION_CONFIG_H

View File

@ -1,19 +1,19 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_RTP_PACKETIZER_H #ifndef RTC_RTP_PACKETIZER_H

View File

@ -22,6 +22,9 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional>
#include <tuple>
#include <utility>
namespace rtc { namespace rtc {
@ -32,11 +35,10 @@ template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
// weak_ptr bind helper // weak_ptr bind helper
template <typename F, typename T, typename... Args> auto weak_bind(F &&f, T *t, Args &&..._args) { template <typename F, typename T, typename... Args> auto weak_bind(F &&f, T *t, Args &&..._args) {
return [bound = std::bind(f, t, _args...), weak_this = t->weak_from_this()](auto &&...args) { return [bound = std::bind(f, t, _args...), weak_this = t->weak_from_this()](auto &&...args) {
using result_type = typename decltype(bound)::result_type;
if (auto shared_this = weak_this.lock()) if (auto shared_this = weak_this.lock())
return bound(args...); return bound(args...);
else else
return static_cast<result_type>(false); return static_cast<decltype(bound(args...))>(false);
}; };
} }
@ -58,40 +60,35 @@ private:
}; };
// callback with built-in synchronization // callback with built-in synchronization
template <typename... Args> class synchronized_callback final { template <typename... Args> class synchronized_callback {
public: public:
synchronized_callback() = default; synchronized_callback() = default;
synchronized_callback(synchronized_callback &&cb) { *this = std::move(cb); } synchronized_callback(synchronized_callback &&cb) { *this = std::move(cb); }
synchronized_callback(const synchronized_callback &cb) { *this = cb; } synchronized_callback(const synchronized_callback &cb) { *this = cb; }
synchronized_callback(std::function<void(Args...)> func) { *this = std::move(func); } synchronized_callback(std::function<void(Args...)> func) { *this = std::move(func); }
~synchronized_callback() { *this = nullptr; } virtual ~synchronized_callback() { *this = nullptr; }
synchronized_callback &operator=(synchronized_callback &&cb) { synchronized_callback &operator=(synchronized_callback &&cb) {
std::scoped_lock lock(mutex, cb.mutex); std::scoped_lock lock(mutex, cb.mutex);
callback = std::move(cb.callback); set(std::exchange(cb.callback, nullptr));
cb.callback = nullptr;
return *this; return *this;
} }
synchronized_callback &operator=(const synchronized_callback &cb) { synchronized_callback &operator=(const synchronized_callback &cb) {
std::scoped_lock lock(mutex, cb.mutex); std::scoped_lock lock(mutex, cb.mutex);
callback = cb.callback; set(cb.callback);
return *this; return *this;
} }
synchronized_callback &operator=(std::function<void(Args...)> func) { synchronized_callback &operator=(std::function<void(Args...)> func) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
callback = std::move(func); set(std::move(func));
return *this; return *this;
} }
bool operator()(Args... args) const { bool operator()(Args... args) const {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (!callback) return call(std::move(args)...);
return false;
callback(std::move(args)...);
return true;
} }
operator bool() const { operator bool() const {
@ -103,11 +100,48 @@ public:
return [this](Args... args) { (*this)(std::move(args)...); }; return [this](Args... args) { (*this)(std::move(args)...); };
} }
private: protected:
virtual void set(std::function<void(Args...)> func) { callback = std::move(func); }
virtual bool call(Args... args) const {
if (!callback)
return false;
callback(std::move(args)...);
return true;
}
std::function<void(Args...)> callback; std::function<void(Args...)> callback;
mutable std::recursive_mutex mutex; mutable std::recursive_mutex mutex;
}; };
// callback with built-in synchronization and replay of the last missed call
template <typename... Args>
class synchronized_stored_callback final : public synchronized_callback<Args...> {
public:
template <typename... CArgs>
synchronized_stored_callback(CArgs &&...cargs)
: synchronized_callback<Args...>(std::forward<CArgs>(cargs)...) {}
~synchronized_stored_callback() {}
private:
void set(std::function<void(Args...)> func) {
synchronized_callback<Args...>::set(func);
if (func && stored) {
std::apply(func, std::move(*stored));
stored.reset();
}
}
bool call(Args... args) const {
if (!synchronized_callback<Args...>::call(args...))
stored.emplace(std::move(args)...);
return true;
}
mutable std::optional<std::tuple<Args...>> stored;
};
// pimpl base class // pimpl base class
template <typename T> using impl_ptr = std::shared_ptr<T>; template <typename T> using impl_ptr = std::shared_ptr<T>;
template <typename T> class CheshireCat { template <typename T> class CheshireCat {

View File

@ -17,7 +17,8 @@
*/ */
#include "candidate.hpp" #include "candidate.hpp"
#include "globals.hpp"
#include "impl/internals.hpp"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -92,7 +93,7 @@ void Candidate::parse(string candidate) {
{"so", TransportType::TcpSo}}; {"so", TransportType::TcpSo}};
const std::array prefixes{"a=", "candidate:"}; const std::array prefixes{"a=", "candidate:"};
for (const string &prefix : prefixes) for (string prefix : prefixes)
if (match_prefix(candidate, prefix)) if (match_prefix(candidate, prefix))
candidate.erase(0, prefix.size()); candidate.erase(0, prefix.size());

View File

@ -17,10 +17,9 @@
*/ */
#include "rtc.h" #include "rtc.h"
#include "rtc.hpp" #include "rtc.hpp"
#include "plog/Formatters/FuncMessageFormatter.h" #include "impl/internals.hpp"
#include <chrono> #include <chrono>
#include <exception> #include <exception>
@ -29,11 +28,6 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#ifdef _WIN32
#include <codecvt>
#include <locale>
#endif
using namespace rtc; using namespace rtc;
using std::chrono::milliseconds; using std::chrono::milliseconds;
@ -116,14 +110,14 @@ int emplaceTrack(shared_ptr<Track> ptr) {
void erasePeerConnection(int pc) { void erasePeerConnection(int pc) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (peerConnectionMap.erase(pc) == 0) if (peerConnectionMap.erase(pc) == 0)
throw std::invalid_argument("PeerConnection ID does not exist"); throw std::invalid_argument("Peer Connection ID does not exist");
userPointerMap.erase(pc); userPointerMap.erase(pc);
} }
void eraseDataChannel(int dc) { void eraseDataChannel(int dc) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (dataChannelMap.erase(dc) == 0) if (dataChannelMap.erase(dc) == 0)
throw std::invalid_argument("DataChannel ID does not exist"); throw std::invalid_argument("Data Channel ID does not exist");
userPointerMap.erase(dc); userPointerMap.erase(dc);
} }
@ -146,7 +140,7 @@ shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) { if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
return it->second; return it->second;
} else { } else {
throw std::invalid_argument("RtcpSRReporter ID does not exist"); throw std::invalid_argument("RTCP SR reporter ID does not exist");
} }
} }
@ -160,7 +154,7 @@ shared_ptr<MediaChainableHandler> getMediaChainableHandler(int id) {
if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) { if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) {
return it->second; return it->second;
} else { } else {
throw std::invalid_argument("RtcpChainableHandler ID does not exist"); throw std::invalid_argument("RTCP chainable handler ID does not exist");
} }
} }
@ -169,44 +163,31 @@ void emplaceMediaChainableHandler(shared_ptr<MediaChainableHandler> ptr, int tr)
rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr)); rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr));
} }
shared_ptr<RtpPacketizationConfig> getRTPConfig(int id) { shared_ptr<RtpPacketizationConfig> getRtpConfig(int id) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) { if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
return it->second; return it->second;
} else { } else {
throw std::invalid_argument("RTPConfiguration ID does not exist"); throw std::invalid_argument("RTP configuration ID does not exist");
} }
} }
void emplaceRTPConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) { void emplaceRtpConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
rtpConfigMap.emplace(std::make_pair(tr, ptr)); rtpConfigMap.emplace(std::make_pair(tr, ptr));
} }
Description::Direction rtcDirectionToDirection(rtcDirection direction) {
switch (direction) {
case RTC_DIRECTION_SENDONLY:
return Description::Direction::SendOnly;
case RTC_DIRECTION_RECVONLY:
return Description::Direction::RecvOnly;
case RTC_DIRECTION_SENDRECV:
return Description::Direction::SendRecv;
case RTC_DIRECTION_INACTIVE:
return Description::Direction::Inactive;
default:
return Description::Direction::Unknown;
}
}
shared_ptr<RtpPacketizationConfig> shared_ptr<RtpPacketizationConfig>
getNewRtpPacketizationConfig(uint32_t ssrc, const char *cname, uint8_t payloadType, createRtpPacketizationConfig(const rtcPacketizationHandlerInit *init) {
uint32_t clockRate, uint16_t sequenceNumber, uint32_t timestamp) { if (!init)
if (!cname) { throw std::invalid_argument("Unexpected null pointer for packetization handler init");
throw std::invalid_argument("Unexpected null pointer for cname");
}
return std::make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, clockRate, if (!init->cname)
sequenceNumber, timestamp); throw std::invalid_argument("Unexpected null pointer for cname");
return std::make_shared<RtpPacketizationConfig>(init->ssrc, init->cname, init->payloadType,
init->clockRate, init->sequenceNumber,
init->timestamp);
} }
#endif // RTC_ENABLE_MEDIA #endif // RTC_ENABLE_MEDIA
@ -287,58 +268,16 @@ int copyAndReturn(binary b, char *buffer, int size) {
return int(b.size()); return int(b.size());
} }
class plogAppender : public plog::IAppender {
public:
plogAppender(rtcLogCallbackFunc cb = nullptr) { setCallback(cb); }
plogAppender(plogAppender &&appender) : callback(nullptr) {
std::lock_guard lock(appender.callbackMutex);
std::swap(appender.callback, callback);
}
void setCallback(rtcLogCallbackFunc cb) {
std::lock_guard lock(callbackMutex);
callback = cb;
}
void write(const plog::Record &record) override {
plog::Severity severity = record.getSeverity();
auto formatted = plog::FuncMessageFormatter::format(record);
formatted.pop_back(); // remove newline
#ifdef _WIN32
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;
std::string str = converter.to_bytes(formatted);
#else
std::string str = formatted;
#endif
std::lock_guard lock(callbackMutex);
if (callback)
callback(static_cast<rtcLogLevel>(record.getSeverity()), str.c_str());
else
std::cout << plog::severityToString(severity) << " " << str << std::endl;
}
private:
rtcLogCallbackFunc callback;
std::mutex callbackMutex;
};
} // namespace } // namespace
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) { void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
static optional<plogAppender> appender; LogCallback callback = nullptr;
const auto severity = static_cast<plog::Severity>(level); if (cb)
std::lock_guard lock(mutex); callback = [cb](LogLevel level, string message) {
if (appender) { cb(static_cast<rtcLogLevel>(level), message.c_str());
appender->setCallback(cb); };
InitLogger(severity, nullptr); // change the severity
} else if (cb) { InitLogger(static_cast<LogLevel>(level), callback);
appender.emplace(plogAppender(cb));
InitLogger(severity, &appender.value());
} else {
InitLogger(severity, nullptr); // log to stdout
}
} }
void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); } void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); }
@ -438,69 +377,65 @@ int rtcDeleteDataChannel(int dc) {
}); });
} }
#if RTC_ENABLE_MEDIA int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
return wrap([&] {
if (!mediaDescriptionSdp)
throw std::invalid_argument("Unexpected null pointer for track media description");
void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid, auto peerConnection = getPeerConnection(pc);
const char *_trackID) { Description::Media media{string(mediaDescriptionSdp)};
int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
if (auto ptr = getUserPointer(pc))
rtcSetUserPointer(tr, *ptr);
optional<string> name = nullopt; return tr;
if (_name) { });
name = string(_name);
}
optional<string> msid = nullopt;
if (_msid) {
msid = string(_msid);
}
optional<string> 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, int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
rtcDirection _direction, const char *_name, const char *_msid,
const char *_trackID) {
return wrap([&] { return wrap([&] {
auto peerConnection = getPeerConnection(pc); auto peerConnection = getPeerConnection(pc);
auto direction = rtcDirectionToDirection(_direction); if (!init)
throw std::invalid_argument("Unexpected null pointer for track init");
string mid = "video"; auto direction = static_cast<Description::Direction>(init->direction);
switch (codec) {
case RTC_CODEC_H264:
case RTC_CODEC_VP8:
case RTC_CODEC_VP9:
mid = "video";
break;
case RTC_CODEC_OPUS:
mid = "audio";
break;
}
if (_mid) { string mid;
mid = string(_mid); if (init->mid) {
mid = string(init->mid);
} else {
switch (init->codec) {
case RTC_CODEC_H264:
case RTC_CODEC_VP8:
case RTC_CODEC_VP9:
mid = "video";
break;
case RTC_CODEC_OPUS:
mid = "audio";
break;
default:
mid = "video";
break;
}
} }
optional<Description::Media> optDescription = nullopt; optional<Description::Media> optDescription = nullopt;
switch (codec) { switch (init->codec) {
case RTC_CODEC_H264: case RTC_CODEC_H264:
case RTC_CODEC_VP8: case RTC_CODEC_VP8:
case RTC_CODEC_VP9: { case RTC_CODEC_VP9: {
auto desc = Description::Video(mid, direction); auto desc = Description::Video(mid, direction);
switch (codec) { switch (init->codec) {
case RTC_CODEC_H264: case RTC_CODEC_H264:
desc.addH264Codec(payloadType); desc.addH264Codec(init->payloadType);
break; break;
case RTC_CODEC_VP8: case RTC_CODEC_VP8:
desc.addVP8Codec(payloadType); desc.addVP8Codec(init->payloadType);
break; break;
case RTC_CODEC_VP9: case RTC_CODEC_VP9:
desc.addVP8Codec(payloadType); desc.addVP8Codec(init->payloadType);
break; break;
default: default:
break; break;
@ -510,9 +445,9 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
} }
case RTC_CODEC_OPUS: { case RTC_CODEC_OPUS: {
auto desc = Description::Audio(mid, direction); auto desc = Description::Audio(mid, direction);
switch (codec) { switch (init->codec) {
case RTC_CODEC_OPUS: case RTC_CODEC_OPUS:
desc.addOpusCodec(payloadType); desc.addOpusCodec(init->payloadType);
break; break;
default: default:
break; break;
@ -524,168 +459,16 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
break; break;
} }
if (!optDescription.has_value()) { if (!optDescription)
throw std::invalid_argument("Unexpected codec"); throw std::invalid_argument("Unexpected codec");
} else {
auto description = optDescription.value();
setSSRC(&description, ssrc, _name, _msid, _trackID);
int tr = emplaceTrack(peerConnection->addTrack(std::move(description))); auto desc = std::move(*optDescription);
if (auto ptr = getUserPointer(pc)) { desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
rtcSetUserPointer(tr, *ptr); init->msid ? std::make_optional(string(init->msid)) : nullopt,
} init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
return tr;
}
});
}
int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char *cname, uint8_t payloadType, int tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
uint32_t clockRate, uint16_t maxFragmentSize,
uint16_t sequenceNumber, uint32_t timestamp) {
return wrap([&] {
auto track = getTrack(tr);
// create RTP configuration
auto rtpConfig = getNewRtpPacketizationConfig(ssrc, cname, payloadType, clockRate,
sequenceNumber, timestamp);
// create packetizer
auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
// create H264 handler
auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
emplaceMediaChainableHandler(h264Handler, tr);
emplaceRTPConfig(rtpConfig, tr);
// set handler
track->setMediaHandler(h264Handler);
return RTC_ERR_SUCCESS;
});
}
int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char *cname, uint8_t payloadType,
uint32_t clockRate, uint16_t sequenceNumber,
uint32_t timestamp) {
return wrap([&] {
auto track = getTrack(tr);
// create RTP configuration
auto rtpConfig = getNewRtpPacketizationConfig(ssrc, cname, payloadType, clockRate,
sequenceNumber, timestamp);
// create packetizer
auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
// create Opus handler
auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
emplaceMediaChainableHandler(opusHandler, tr);
emplaceRTPConfig(rtpConfig, tr);
// set handler
track->setMediaHandler(opusHandler);
return RTC_ERR_SUCCESS;
});
}
int rtcChainRtcpSrReporter(int tr) {
return wrap([tr] {
auto config = getRTPConfig(tr);
auto reporter = std::make_shared<RtcpSrReporter>(config);
emplaceRtcpSrReporter(reporter, tr);
auto chainableHandler = getMediaChainableHandler(tr);
chainableHandler->addToChain(reporter);
return RTC_ERR_SUCCESS;
});
}
int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount) {
return wrap([tr, maxStoredPacketsCount] {
auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
auto chainableHandler = getMediaChainableHandler(tr);
chainableHandler->addToChain(responder);
return RTC_ERR_SUCCESS;
});
}
int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970,
uint32_t timestamp) {
return wrap([&] {
auto config = getRTPConfig(id);
auto epoch = RtpPacketizationConfig::EpochStart::T1900;
if (timeIntervalSince1970) {
epoch = RtpPacketizationConfig::EpochStart::T1970;
}
config->setStartTime(startTime_s, epoch, timestamp);
return RTC_ERR_SUCCESS;
});
}
int rtcStartRtcpSenderReporterRecording(int id) {
return wrap([id] {
auto sender = getRtcpSrReporter(id);
sender->startRecording();
return RTC_ERR_SUCCESS;
});
}
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
return wrap([&] {
auto config = getRTPConfig(id);
*timestamp = config->secondsToTimestamp(seconds);
return RTC_ERR_SUCCESS;
});
}
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
return wrap([&] {
auto config = getRTPConfig(id);
*seconds = config->timestampToSeconds(timestamp);
return RTC_ERR_SUCCESS;
});
}
int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
return wrap([&] {
auto config = getRTPConfig(id);
*timestamp = config->timestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
return wrap([&] {
auto config = getRTPConfig(id);
*timestamp = config->startTimestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp) {
return wrap([&] {
auto config = getRTPConfig(id);
config->timestamp = timestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
return wrap([&] {
auto sender = getRtcpSrReporter(id);
*timestamp = sender->previousReportedTimestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcSetNeedsToSendRtcpSr(int id) {
return wrap([id] {
auto sender = getRtcpSrReporter(id);
sender->setNeedsToReport();
return RTC_ERR_SUCCESS;
});
}
#endif // RTC_ENABLE_MEDIA
int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
return wrap([&] {
if (!mediaDescriptionSdp)
throw std::invalid_argument("Unexpected null pointer for track media description");
auto peerConnection = getPeerConnection(pc);
Description::Media media{string(mediaDescriptionSdp)};
int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
if (auto ptr = getUserPointer(pc)) if (auto ptr = getUserPointer(pc))
rtcSetUserPointer(tr, *ptr); rtcSetUserPointer(tr, *ptr);
@ -715,7 +498,141 @@ int rtcGetTrackDescription(int tr, char *buffer, int size) {
}); });
} }
#if RTC_ENABLE_MEDIA
int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
return wrap([&] {
auto track = getTrack(tr);
// create RTP configuration
auto rtpConfig = createRtpPacketizationConfig(init);
// create packetizer
auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize
: RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE;
auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
// create H264 handler
auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
emplaceMediaChainableHandler(h264Handler, tr);
emplaceRtpConfig(rtpConfig, tr);
// set handler
track->setMediaHandler(h264Handler);
return RTC_ERR_SUCCESS;
});
}
int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
return wrap([&] {
auto track = getTrack(tr);
// create RTP configuration
auto rtpConfig = createRtpPacketizationConfig(init);
// create packetizer
auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
// create Opus handler
auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
emplaceMediaChainableHandler(opusHandler, tr);
emplaceRtpConfig(rtpConfig, tr);
// set handler
track->setMediaHandler(opusHandler);
return RTC_ERR_SUCCESS;
});
}
int rtcChainRtcpSrReporter(int tr) {
return wrap([tr] {
auto config = getRtpConfig(tr);
auto reporter = std::make_shared<RtcpSrReporter>(config);
emplaceRtcpSrReporter(reporter, tr);
auto chainableHandler = getMediaChainableHandler(tr);
chainableHandler->addToChain(reporter);
return RTC_ERR_SUCCESS;
});
}
int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
return wrap([tr, maxStoredPacketsCount] {
auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
auto chainableHandler = getMediaChainableHandler(tr);
chainableHandler->addToChain(responder);
return RTC_ERR_SUCCESS;
});
}
int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime) {
return wrap([&] {
auto config = getRtpConfig(id);
auto epoch = startTime->since1970 ? RtpPacketizationConfig::EpochStart::T1970
: RtpPacketizationConfig::EpochStart::T1900;
config->setStartTime(startTime->seconds, epoch, startTime->timestamp);
return RTC_ERR_SUCCESS;
});
}
int rtcStartRtcpSenderReporterRecording(int id) {
return wrap([id] {
auto sender = getRtcpSrReporter(id);
sender->startRecording();
return RTC_ERR_SUCCESS;
});
}
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
return wrap([&] {
auto config = getRtpConfig(id);
*timestamp = config->secondsToTimestamp(seconds);
return RTC_ERR_SUCCESS;
});
}
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
return wrap([&] {
auto config = getRtpConfig(id);
*seconds = config->timestampToSeconds(timestamp);
return RTC_ERR_SUCCESS;
});
}
int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
return wrap([&] {
auto config = getRtpConfig(id);
*timestamp = config->timestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
return wrap([&] {
auto config = getRtpConfig(id);
*timestamp = config->startTimestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) {
return wrap([&] {
auto config = getRtpConfig(id);
config->timestamp = timestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
return wrap([&] {
auto sender = getRtcpSrReporter(id);
*timestamp = sender->previousReportedTimestamp;
return RTC_ERR_SUCCESS;
});
}
int rtcSetNeedsToSendRtcpSr(int id) {
return wrap([id] {
auto sender = getRtcpSrReporter(id);
sender->setNeedsToReport();
return RTC_ERR_SUCCESS;
});
}
#endif // RTC_ENABLE_MEDIA
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
int rtcCreateWebSocket(const char *url) { int rtcCreateWebSocket(const char *url) {
return wrap([&] { return wrap([&] {
auto ws = std::make_shared<WebSocket>(); auto ws = std::make_shared<WebSocket>();
@ -748,6 +665,7 @@ int rtcDeleteWebsocket(int ws) {
return RTC_ERR_SUCCESS; return RTC_ERR_SUCCESS;
}); });
} }
#endif #endif
int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) { int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
@ -1189,4 +1107,37 @@ int rtcReceiveMessage(int id, char *buffer, int *size) {
} }
void rtcPreload() { rtc::Preload(); } void rtcPreload() { rtc::Preload(); }
void rtcCleanup() { rtc::Cleanup(); } void rtcCleanup() { rtc::Cleanup(); }
int rtcSetSctpSettings(const rtcSctpSettings *settings) {
return wrap([&] {
SctpSettings s = {};
if (settings->recvBufferSize > 0)
s.recvBufferSize = size_t(settings->recvBufferSize);
if (settings->sendBufferSize > 0)
s.sendBufferSize = size_t(settings->sendBufferSize);
if (settings->maxChunksOnQueue > 0)
s.maxChunksOnQueue = size_t(settings->maxChunksOnQueue);
if (settings->initialCongestionWindow > 0)
s.initialCongestionWindow = size_t(settings->initialCongestionWindow);
if (settings->maxBurst > 0)
s.maxBurst = size_t(settings->maxBurst);
else if (settings->maxBurst < 0)
s.maxBurst = size_t(0); // setting to 0 disables, not setting chooses optimized default
if (settings->congestionControlModule >= 0)
s.congestionControlModule = unsigned(settings->congestionControlModule);
if (settings->delayedSackTimeMs > 0)
s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
SetSctpSettings(std::move(s));
return RTC_ERR_SUCCESS;
});
}

View File

@ -17,8 +17,8 @@
*/ */
#include "channel.hpp" #include "channel.hpp"
#include "globals.hpp"
#include "impl/internals.hpp"
#include "impl/channel.hpp" #include "impl/channel.hpp"
namespace rtc { namespace rtc {
@ -43,10 +43,7 @@ void Channel::onError(std::function<void(string error)> callback) {
void Channel::onMessage(std::function<void(message_variant data)> callback) { void Channel::onMessage(std::function<void(message_variant data)> callback) {
impl()->messageCallback = callback; impl()->messageCallback = callback;
impl()->flushPendingMessages();
// Pass pending messages
while (auto message = receive())
impl()->messageCallback(*message);
} }
void Channel::onMessage(std::function<void(binary data)> binaryCallback, void Channel::onMessage(std::function<void(binary data)> binaryCallback,

View File

@ -17,11 +17,11 @@
*/ */
#include "datachannel.hpp" #include "datachannel.hpp"
#include "globals.hpp"
#include "common.hpp" #include "common.hpp"
#include "peerconnection.hpp" #include "peerconnection.hpp"
#include "impl/datachannel.hpp" #include "impl/datachannel.hpp"
#include "impl/internals.hpp"
#include "impl/peerconnection.hpp" #include "impl/peerconnection.hpp"
#ifdef _WIN32 #ifdef _WIN32

View File

@ -19,6 +19,8 @@
#include "description.hpp" #include "description.hpp"
#include "impl/internals.hpp"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cctype> #include <cctype>
@ -978,18 +980,17 @@ std::ostream &operator<<(std::ostream &out, rtc::Description::Type type) {
std::ostream &operator<<(std::ostream &out, rtc::Description::Role role) { std::ostream &operator<<(std::ostream &out, rtc::Description::Role role) {
using Role = rtc::Description::Role; using Role = rtc::Description::Role;
const char *str;
// Used for SDP generation, do not change // Used for SDP generation, do not change
switch (role) { switch (role) {
case Role::Active: case Role::Active:
str = "active"; out << "active";
break; break;
case Role::Passive: case Role::Passive:
str = "passive"; out << "passive";
break; break;
default: default:
str = "actpass"; out << "actpass";
break; break;
} }
return out << str; return out;
} }

123
src/global.cpp Normal file
View File

@ -0,0 +1,123 @@
/**
* Copyright (c) 2020-2021 Paul-Louis Ageneau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "plog/Appenders/ColorConsoleAppender.h"
#include "plog/Formatters/FuncMessageFormatter.h"
#include "plog/Formatters/TxtFormatter.h"
#include "plog/Init.h"
#include "plog/Log.h"
#include "plog/Logger.h"
//
#include "global.hpp"
#include "impl/init.hpp"
#include <mutex>
#ifdef _WIN32
#include <codecvt>
#include <locale>
#endif
namespace rtc {
struct LogAppender : public plog::IAppender {
synchronized_callback<LogLevel, string> callback;
void write(const plog::Record &record) override {
const auto severity = record.getSeverity();
auto formatted = plog::FuncMessageFormatter::format(record);
formatted.pop_back(); // remove newline
#ifdef _WIN32
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;
std::string str = converter.to_bytes(formatted);
#else
std::string str = formatted;
#endif
if (!callback(static_cast<LogLevel>(severity), str))
std::cout << plog::severityToString(severity) << " " << str << std::endl;
}
};
void InitLogger(LogLevel level, LogCallback callback) {
static unique_ptr<LogAppender> appender;
const auto severity = static_cast<plog::Severity>(level);
if (appender) {
appender->callback = std::move(callback);
InitLogger(severity, nullptr); // change the severity
} else if (callback) {
appender = std::make_unique<LogAppender>();
appender->callback = std::move(callback);
InitLogger(severity, appender.get());
} else {
InitLogger(severity, nullptr); // log to cout
}
}
void InitLogger(plog::Severity severity, plog::IAppender *appender) {
static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
static plog::Logger<0> *logger = nullptr;
static std::mutex mutex;
std::lock_guard lock(mutex);
if (!logger) {
logger = &plog::init(severity, appender ? appender : &consoleAppender);
PLOG_DEBUG << "Logger initialized";
} else {
logger->setMaxSeverity(severity);
if (appender)
logger->addAppender(appender);
}
}
void Preload() { Init::Preload(); }
void Cleanup() { Init::Cleanup(); }
void SetSctpSettings(SctpSettings s) { Init::SetSctpSettings(std::move(s)); }
} // namespace rtc
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level) {
switch (level) {
case rtc::LogLevel::Fatal:
out << "fatal";
break;
case rtc::LogLevel::Error:
out << "error";
break;
case rtc::LogLevel::Warning:
out << "warning";
break;
case rtc::LogLevel::Info:
out << "info";
break;
case rtc::LogLevel::Debug:
out << "debug";
break;
case rtc::LogLevel::Verbose:
out << "verbose";
break;
default:
out << "none";
break;
}
return out;
}

View File

@ -1,19 +1,19 @@
/* /**
* libdatachannel client example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA

View File

@ -1,25 +1,35 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "h264rtppacketizer.hpp" #include "h264rtppacketizer.hpp"
#include "impl/internals.hpp"
#include <cassert>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
namespace rtc { namespace rtc {
typedef enum { typedef enum {

View File

@ -20,22 +20,21 @@
namespace rtc::impl { namespace rtc::impl {
void Channel::triggerOpen() { openCallback(); } void Channel::triggerOpen() {
mOpenTriggered = true;
openCallback();
flushPendingMessages();
}
void Channel::triggerClosed() { closedCallback(); } void Channel::triggerClosed() { closedCallback(); }
void Channel::triggerError(string error) { errorCallback(error); } void Channel::triggerError(string error) { errorCallback(std::move(error)); }
void Channel::triggerAvailable(size_t count) { void Channel::triggerAvailable(size_t count) {
if (count == 1) if (count == 1)
availableCallback(); availableCallback();
while (messageCallback && count--) { flushPendingMessages();
auto message = receive();
if (!message)
break;
messageCallback(*message);
}
} }
void Channel::triggerBufferedAmount(size_t amount) { void Channel::triggerBufferedAmount(size_t amount) {
@ -45,13 +44,32 @@ void Channel::triggerBufferedAmount(size_t amount) {
bufferedAmountLowCallback(); bufferedAmountLowCallback();
} }
void Channel::flushPendingMessages() {
if (!mOpenTriggered)
return;
while (messageCallback) {
auto next = receive();
if (!next)
break;
messageCallback(*next);
}
}
void Channel::resetOpenCallback() {
mOpenTriggered = false;
openCallback = nullptr;
}
void Channel::resetCallbacks() { void Channel::resetCallbacks() {
mOpenTriggered = false;
openCallback = nullptr; openCallback = nullptr;
closedCallback = nullptr; closedCallback = nullptr;
errorCallback = nullptr; errorCallback = nullptr;
messageCallback = nullptr;
availableCallback = nullptr; availableCallback = nullptr;
bufferedAmountLowCallback = nullptr; bufferedAmountLowCallback = nullptr;
messageCallback = nullptr;
} }
} // namespace rtc::impl } // namespace rtc::impl

View File

@ -38,17 +38,23 @@ struct Channel {
virtual void triggerAvailable(size_t count); virtual void triggerAvailable(size_t count);
virtual void triggerBufferedAmount(size_t amount); virtual void triggerBufferedAmount(size_t amount);
virtual void resetCallbacks(); void flushPendingMessages();
void resetOpenCallback();
void resetCallbacks();
synchronized_stored_callback<> openCallback;
synchronized_stored_callback<> closedCallback;
synchronized_stored_callback<string> errorCallback;
synchronized_stored_callback<> availableCallback;
synchronized_stored_callback<> bufferedAmountLowCallback;
synchronized_callback<> openCallback;
synchronized_callback<> closedCallback;
synchronized_callback<string> errorCallback;
synchronized_callback<message_variant> messageCallback; synchronized_callback<message_variant> messageCallback;
synchronized_callback<> availableCallback;
synchronized_callback<> bufferedAmountLowCallback;
std::atomic<size_t> bufferedAmount = 0; std::atomic<size_t> bufferedAmount = 0;
std::atomic<size_t> bufferedAmountLowThreshold = 0; std::atomic<size_t> bufferedAmountLowThreshold = 0;
private:
std::atomic<bool> mOpenTriggered = false;
}; };
} // namespace rtc::impl } // namespace rtc::impl

View File

@ -18,7 +18,7 @@
#include "datachannel.hpp" #include "datachannel.hpp"
#include "common.hpp" #include "common.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "logcounter.hpp" #include "logcounter.hpp"
#include "peerconnection.hpp" #include "peerconnection.hpp"
#include "sctptransport.hpp" #include "sctptransport.hpp"

View File

@ -36,7 +36,7 @@ struct PeerConnection;
struct DataChannel : Channel, std::enable_shared_from_this<DataChannel> { struct DataChannel : Channel, std::enable_shared_from_this<DataChannel> {
DataChannel(weak_ptr<PeerConnection> pc, uint16_t stream, string label, string protocol, DataChannel(weak_ptr<PeerConnection> pc, uint16_t stream, string label, string protocol,
Reliability reliability); Reliability reliability);
~DataChannel(); virtual ~DataChannel();
void close(); void close();
void remoteClose(); void remoteClose();

View File

@ -17,7 +17,7 @@
*/ */
#include "dtlstransport.hpp" #include "dtlstransport.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "icetransport.hpp" #include "icetransport.hpp"
#include <chrono> #include <chrono>

View File

@ -18,7 +18,7 @@
#include "icetransport.hpp" #include "icetransport.hpp"
#include "configuration.hpp" #include "configuration.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "transport.hpp" #include "transport.hpp"
#include <iostream> #include <iostream>

View File

@ -17,7 +17,7 @@
*/ */
#include "init.hpp" #include "init.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "impl/certificate.hpp" #include "impl/certificate.hpp"
#include "impl/dtlstransport.hpp" #include "impl/dtlstransport.hpp"
@ -42,7 +42,6 @@ namespace rtc {
namespace { namespace {
void doInit() { void doInit() {
PLOG_DEBUG << "Global initialization";
#ifdef _WIN32 #ifdef _WIN32
WSADATA wsaData; WSADATA wsaData;
@ -69,8 +68,6 @@ void doInit() {
} }
void doCleanup() { void doCleanup() {
PLOG_DEBUG << "Global cleanup";
impl::ThreadPool::Instance().join(); impl::ThreadPool::Instance().join();
impl::SctpTransport::Cleanup(); impl::SctpTransport::Cleanup();
@ -92,6 +89,7 @@ void doCleanup() {
weak_ptr<void> Init::Weak; weak_ptr<void> Init::Weak;
shared_ptr<void> *Init::Global = nullptr; shared_ptr<void> *Init::Global = nullptr;
bool Init::Initialized = false; bool Init::Initialized = false;
SctpSettings Init::CurrentSctpSettings = {};
std::recursive_mutex Init::Mutex; std::recursive_mutex Init::Mutex;
init_token Init::Token() { init_token Init::Token() {
@ -118,10 +116,20 @@ void Init::Cleanup() {
Global = nullptr; Global = nullptr;
} }
void Init::SetSctpSettings(SctpSettings s) {
auto token = Token();
std::unique_lock lock(Mutex);
impl::SctpTransport::SetSettings(s);
CurrentSctpSettings = std::move(s); // store for next init
}
Init::Init() { Init::Init() {
// Mutex is locked by Token() here // Mutex is locked by Token() here
if (!std::exchange(Initialized, true)) if (!std::exchange(Initialized, true)) {
PLOG_DEBUG << "Global initialization";
doInit(); doInit();
impl::SctpTransport::SetSettings(CurrentSctpSettings);
}
} }
Init::~Init() { Init::~Init() {
@ -130,8 +138,11 @@ Init::~Init() {
std::unique_lock lock(Mutex); std::unique_lock lock(Mutex);
if (Global) if (Global)
return; return;
if (std::exchange(Initialized, false))
if (std::exchange(Initialized, false)) {
PLOG_DEBUG << "Global cleanup";
doCleanup(); doCleanup();
}
}); });
t.detach(); t.detach();
} }

View File

@ -16,22 +16,25 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_INIT_H #ifndef RTC_IMPL_INIT_H
#define RTC_INIT_H #define RTC_IMPL_INIT_H
#include "common.hpp" #include "common.hpp"
#include "global.hpp" // for SctpSettings
#include <chrono>
#include <mutex> #include <mutex>
namespace rtc { namespace rtc {
using init_token = shared_ptr<void>; using init_token = shared_ptr<void>;
class RTC_CPP_EXPORT Init { class Init {
public: public:
static init_token Token(); static init_token Token();
static void Preload(); static void Preload();
static void Cleanup(); static void Cleanup();
static void SetSctpSettings(SctpSettings s);
~Init(); ~Init();
@ -41,12 +44,10 @@ private:
static weak_ptr<void> Weak; static weak_ptr<void> Weak;
static shared_ptr<void> *Global; static shared_ptr<void> *Global;
static bool Initialized; static bool Initialized;
static SctpSettings CurrentSctpSettings;
static std::recursive_mutex Mutex; static std::recursive_mutex Mutex;
}; };
inline void Preload() { Init::Preload(); }
inline void Cleanup() { Init::Cleanup(); }
} // namespace rtc } // namespace rtc
#endif #endif

View File

@ -16,17 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef RTC_GLOBALS_H #ifndef RTC_IMPL_INTERNALS_H
#define RTC_GLOBALS_H #define RTC_IMPL_INTERNALS_H
#include "common.hpp" #include "common.hpp"
// Disable warnings before including plog
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#elif defined(_MSC_VER)
#pragma warning(push, 0)
#endif
#include "plog/Log.h"
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif
namespace rtc { namespace rtc {
const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length
const size_t MAX_NUMERICSERV_LEN = 6; // Max port string representation length const size_t MAX_NUMERICSERV_LEN = 6; // Max port string representation length
const uint16_t DEFAULT_SCTP_PORT = 5000; // SCTP port to use by default const uint16_t DEFAULT_SCTP_PORT = 5000; // SCTP port to use by default
const size_t DEFAULT_LOCAL_MAX_MESSAGE_SIZE = 256 * 1024; // Default local max message size const size_t DEFAULT_LOCAL_MAX_MESSAGE_SIZE = 256 * 1024; // Default local max message size
const size_t DEFAULT_MAX_MESSAGE_SIZE = 65536; // Remote max message size if not specified in SDP const size_t DEFAULT_MAX_MESSAGE_SIZE = 65536; // Remote max message size if not specified in SDP

View File

@ -21,7 +21,7 @@
#include "certificate.hpp" #include "certificate.hpp"
#include "common.hpp" #include "common.hpp"
#include "dtlstransport.hpp" #include "dtlstransport.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "icetransport.hpp" #include "icetransport.hpp"
#include "logcounter.hpp" #include "logcounter.hpp"
#include "peerconnection.hpp" #include "peerconnection.hpp"
@ -189,7 +189,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
auto certificate = mCertificate.get(); auto certificate = mCertificate.get();
auto lower = std::atomic_load(&mIceTransport); auto lower = std::atomic_load(&mIceTransport);
auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1); auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1);
auto stateChangeCallback = auto dtlsStateChangeCallback =
[this, weak_this = weak_from_this()](DtlsTransport::State transportState) { [this, weak_this = weak_from_this()](DtlsTransport::State transportState) {
auto shared_this = weak_this.lock(); auto shared_this = weak_this.lock();
if (!shared_this) if (!shared_this)
@ -224,7 +224,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
// DTLS-SRTP // DTLS-SRTP
transport = std::make_shared<DtlsSrtpTransport>( transport = std::make_shared<DtlsSrtpTransport>(
lower, certificate, config.mtu, verifierCallback, lower, certificate, config.mtu, verifierCallback,
weak_bind(&PeerConnection::forwardMedia, this, _1), stateChangeCallback); weak_bind(&PeerConnection::forwardMedia, this, _1), dtlsStateChangeCallback);
#else #else
PLOG_WARNING << "Ignoring media support (not compiled with media support)"; PLOG_WARNING << "Ignoring media support (not compiled with media support)";
#endif #endif
@ -233,7 +233,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
if (!transport) { if (!transport) {
// DTLS only // DTLS only
transport = std::make_shared<DtlsTransport>(lower, certificate, config.mtu, transport = std::make_shared<DtlsTransport>(lower, certificate, config.mtu,
verifierCallback, stateChangeCallback); verifierCallback, dtlsStateChangeCallback);
} }
std::atomic_store(&mDtlsTransport, transport); std::atomic_store(&mDtlsTransport, transport);
@ -440,8 +440,8 @@ void PeerConnection::forwardMedia(message_ptr message) {
offset += header->lengthInBytes(); offset += header->lengthInBytes();
if (header->payloadType() == 205 || header->payloadType() == 206) { if (header->payloadType() == 205 || header->payloadType() == 206) {
auto rtcpfb = reinterpret_cast<RTCP_FB_HEADER *>(header); auto rtcpfb = reinterpret_cast<RTCP_FB_HEADER *>(header);
ssrcs.insert(rtcpfb->getPacketSenderSSRC()); ssrcs.insert(rtcpfb->packetSenderSSRC());
ssrcs.insert(rtcpfb->getMediaSourceSSRC()); ssrcs.insert(rtcpfb->mediaSourceSSRC());
} else if (header->payloadType() == 200 || header->payloadType() == 201) { } else if (header->payloadType() == 200 || header->payloadType() == 201) {
auto rtcpsr = reinterpret_cast<RTCP_SR *>(header); auto rtcpsr = reinterpret_cast<RTCP_SR *>(header);
@ -738,7 +738,7 @@ void PeerConnection::validateRemoteDescription(const Description &description) {
} }
void PeerConnection::processLocalDescription(Description description) { void PeerConnection::processLocalDescription(Description description) {
const size_t localSctpPort = DEFAULT_SCTP_PORT; const uint16_t localSctpPort = DEFAULT_SCTP_PORT;
const size_t localMaxMessageSize = const size_t localMaxMessageSize =
config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE); config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
@ -973,33 +973,54 @@ string PeerConnection::localBundleMid() const {
void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) { void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
auto dataChannel = weakDataChannel.lock(); auto dataChannel = weakDataChannel.lock();
if (dataChannel) if (dataChannel) {
dataChannel->resetOpenCallback(); // might be set internally
mPendingDataChannels.push(std::move(dataChannel)); mPendingDataChannels.push(std::move(dataChannel));
}
triggerPendingDataChannels();
}
void PeerConnection::triggerTrack(weak_ptr<Track> weakTrack) {
auto track = weakTrack.lock();
if (track) {
track->resetOpenCallback(); // might be set internally
mPendingTracks.push(std::move(track));
}
triggerPendingTracks();
}
void PeerConnection::triggerPendingDataChannels() {
while (dataChannelCallback) { while (dataChannelCallback) {
auto next = mPendingDataChannels.tryPop(); auto next = mPendingDataChannels.tryPop();
if (!next) if (!next)
break; break;
mProcessor->enqueue(dataChannelCallback.wrap(), auto impl = std::move(*next);
std::make_shared<rtc::DataChannel>(std::move(*next))); dataChannelCallback(std::make_shared<rtc::DataChannel>(impl));
impl->triggerOpen();
} }
} }
void PeerConnection::triggerTrack(weak_ptr<Track> weakTrack) { void PeerConnection::triggerPendingTracks() {
auto track = weakTrack.lock();
if (track)
mPendingTracks.push(std::move(track));
while (trackCallback) { while (trackCallback) {
auto next = mPendingTracks.tryPop(); auto next = mPendingTracks.tryPop();
if (!next) if (!next)
break; break;
mProcessor->enqueue(trackCallback.wrap(), std::make_shared<rtc::Track>(std::move(*next))); auto impl = std::move(*next);
trackCallback(std::make_shared<rtc::Track>(impl));
impl->triggerOpen();
} }
} }
void PeerConnection::flushPendingDataChannels() {
mProcessor->enqueue(std::bind(&PeerConnection::triggerPendingDataChannels, this));
}
void PeerConnection::flushPendingTracks() {
mProcessor->enqueue(std::bind(&PeerConnection::triggerPendingTracks, this));
}
bool PeerConnection::changeState(State newState) { bool PeerConnection::changeState(State newState) {
State current; State current;
do { do {

View File

@ -84,8 +84,14 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
void processRemoteCandidate(Candidate candidate); void processRemoteCandidate(Candidate candidate);
string localBundleMid() const; string localBundleMid() const;
void triggerDataChannel(weak_ptr<DataChannel> weakDataChannel = {}); void triggerDataChannel(weak_ptr<DataChannel> weakDataChannel);
void triggerTrack(weak_ptr<Track> weakTrack = {}); void triggerTrack(weak_ptr<Track> weakTrack);
void triggerPendingDataChannels();
void triggerPendingTracks();
void flushPendingDataChannels();
void flushPendingTracks();
bool changeState(State newState); bool changeState(State newState);
bool changeGatheringState(GatheringState newState); bool changeGatheringState(GatheringState newState);

View File

@ -18,12 +18,13 @@
#include "sctptransport.hpp" #include "sctptransport.hpp"
#include "dtlstransport.hpp" #include "dtlstransport.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "logcounter.hpp" #include "logcounter.hpp"
#include <chrono> #include <chrono>
#include <exception> #include <exception>
#include <iostream> #include <iostream>
#include <limits>
#include <thread> #include <thread>
#include <vector> #include <vector>
@ -54,6 +55,26 @@
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace std::chrono; using namespace std::chrono;
namespace {
template <typename T> uint16_t to_uint16(T i) {
if (i >= 0 && static_cast<typename std::make_unsigned<T>::type>(i) <=
std::numeric_limits<uint16_t>::max())
return static_cast<uint16_t>(i);
else
throw std::invalid_argument("Integer out of range");
}
template <typename T> uint32_t to_uint32(T i) {
if (i >= 0 && static_cast<typename std::make_unsigned<T>::type>(i) <=
std::numeric_limits<uint32_t>::max())
return static_cast<uint32_t>(i);
else
throw std::invalid_argument("Integer out of range");
}
} // namespace
namespace rtc::impl { namespace rtc::impl {
static LogCounter COUNTER_UNKNOWN_PPID(plog::warning, static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
@ -64,12 +85,35 @@ static LogCounter
static LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning, static LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning,
"Number of SCTP packets received with a bad status"); "Number of SCTP packets received with a bad status");
std::unordered_set<SctpTransport *> SctpTransport::Instances; class SctpTransport::InstancesSet {
std::shared_mutex SctpTransport::InstancesMutex; public:
void insert(SctpTransport *instance) {
std::unique_lock lock(mMutex);
mSet.insert(instance);
}
void erase(SctpTransport *instance) {
std::unique_lock lock(mMutex);
mSet.erase(instance);
}
using shared_lock = std::shared_lock<std::shared_mutex>;
optional<shared_lock> lock(SctpTransport *instance) {
shared_lock lock(mMutex);
return mSet.find(instance) != mSet.end() ? std::make_optional(std::move(lock)) : nullopt;
}
private:
std::unordered_set<SctpTransport *> mSet;
std::shared_mutex mMutex;
};
SctpTransport::InstancesSet *SctpTransport::Instances = new InstancesSet;
void SctpTransport::Init() { void SctpTransport::Init() {
usrsctp_init(0, &SctpTransport::WriteCallback, nullptr); usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
usrsctp_sysctl_set_sctp_ecn_enable(0); usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758)
usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification
usrsctp_sysctl_set_sctp_init_rtx_max_default(5); usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
usrsctp_sysctl_set_sctp_path_rtx_max_default(5); usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path
@ -78,21 +122,31 @@ void SctpTransport::Init() {
usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms
usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms
usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
}
usrsctp_sysctl_set_sctp_max_chunks_on_queue(10 * 1024); void SctpTransport::SetSettings(const SctpSettings &s) {
// The send and receive window size of usrsctp is 256KiB, which is too small for realistic RTTs,
// therefore we increase it to 1MiB by default for better performance.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
usrsctp_sysctl_set_sctp_recvspace(to_uint32(s.recvBufferSize.value_or(1024 * 1024)));
usrsctp_sysctl_set_sctp_sendspace(to_uint32(s.sendBufferSize.value_or(1024 * 1024)));
// Use default congestion control (RFC 4960) // Increase maximum chunks number on queue to 10K by default
usrsctp_sysctl_set_sctp_max_chunks_on_queue(to_uint32(s.maxChunksOnQueue.value_or(10 * 1024)));
// Increase initial congestion window size to 10 MTUs (RFC 6928) by default
usrsctp_sysctl_set_sctp_initial_cwnd(to_uint32(s.initialCongestionWindow.value_or(10)));
// Set max burst to 10 MTUs by default (max burst is initially 0, meaning disabled)
usrsctp_sysctl_set_sctp_max_burst_default(to_uint32(s.maxBurst.value_or(10)));
// Use standard SCTP congestion control (RFC 4960) by default
// See https://github.com/paullouisageneau/libdatachannel/issues/354 // See https://github.com/paullouisageneau/libdatachannel/issues/354
usrsctp_sysctl_set_sctp_default_cc_module(0); usrsctp_sysctl_set_sctp_default_cc_module(to_uint32(s.congestionControlModule.value_or(0)));
// Enable Partial Reliability Extension (RFC 3758) // Reduce SACK delay to 20ms by default
usrsctp_sysctl_set_sctp_pr_enable(1); usrsctp_sysctl_set_sctp_delayed_sack_time_default(
to_uint32(s.delayedSackTime.value_or(20ms).count()));
// Increase the initial window size to 10 MTUs (RFC 6928)
usrsctp_sysctl_set_sctp_initial_cwnd(10);
// Reduce SACK delay from the default 200ms to 20ms
usrsctp_sysctl_set_sctp_delayed_sack_time_default(20); // ms
} }
void SctpTransport::Cleanup() { void SctpTransport::Cleanup() {
@ -111,10 +165,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
PLOG_DEBUG << "Initializing SCTP transport"; PLOG_DEBUG << "Initializing SCTP transport";
usrsctp_register_address(this); usrsctp_register_address(this);
{ Instances->insert(this);
std::unique_lock lock(InstancesMutex);
Instances.insert(this);
}
mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, nullptr, nullptr, 0, nullptr); mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, nullptr, nullptr, 0, nullptr);
if (!mSock) if (!mSock)
@ -195,7 +246,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
// The MTU value provided specifies the space available for chunks in the // The MTU value provided specifies the space available for chunks in the
// packet, so we also subtract the SCTP header size. // packet, so we also subtract the SCTP header size.
size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 37 - 8 - 40; // SCTP/DTLS/UDP/IPv6 size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 37 - 8 - 40; // SCTP/DTLS/UDP/IPv6
spp.spp_pathmtu = uint32_t(pmtu); spp.spp_pathmtu = to_uint32(pmtu);
PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu; PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu;
} }
@ -222,18 +273,28 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" + throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
std::to_string(errno)); std::to_string(errno));
// The default send and receive window size of usrsctp is 256KiB, which is too small for int rcvBuf = 0;
// realistic RTTs, therefore we increase it to at least 1MiB for better performance. socklen_t rcvBufLen = sizeof(rcvBuf);
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685 if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen))
const size_t minBufferSize = 1024 * 1024; throw std::runtime_error("Could not get SCTP recv buffer size, errno=" +
std::to_string(errno));
int sndBuf = 0;
socklen_t sndBufLen = sizeof(sndBuf);
if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, &sndBufLen))
throw std::runtime_error("Could not get SCTP send buffer size, errno=" +
std::to_string(errno));
// Ensure the buffer is also large enough to accomodate the largest messages // Ensure the buffer is also large enough to accomodate the largest messages
const size_t maxMessageSize = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE); const size_t maxMessageSize = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
const int bufferSize = int(std::max(minBufferSize, maxMessageSize * 2)); // usrsctp reads as int const int minBuf = int(std::min(maxMessageSize, size_t(std::numeric_limits<int>::max())));
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize))) rcvBuf = std::max(rcvBuf, minBuf);
sndBuf = std::max(sndBuf, minBuf);
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, sizeof(rcvBuf)))
throw std::runtime_error("Could not set SCTP recv buffer size, errno=" + throw std::runtime_error("Could not set SCTP recv buffer size, errno=" +
std::to_string(errno)); std::to_string(errno));
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)))
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, sizeof(sndBuf)))
throw std::runtime_error("Could not set SCTP send buffer size, errno=" + throw std::runtime_error("Could not set SCTP send buffer size, errno=" +
std::to_string(errno)); std::to_string(errno));
} }
@ -243,10 +304,7 @@ SctpTransport::~SctpTransport() {
close(); close();
usrsctp_deregister_address(this); usrsctp_deregister_address(this);
{ Instances->erase(this);
std::unique_lock lock(InstancesMutex);
Instances.erase(this);
}
} }
void SctpTransport::start() { void SctpTransport::start() {
@ -336,7 +394,7 @@ bool SctpTransport::send(message_ptr message) {
return true; return true;
mSendQueue.push(message); mSendQueue.push(message);
updateBufferedAmount(uint16_t(message->stream), long(message_size_func(message))); updateBufferedAmount(to_uint16(message->stream), ptrdiff_t(message_size_func(message)));
return false; return false;
} }
@ -353,7 +411,7 @@ bool SctpTransport::flush() {
} }
void SctpTransport::closeStream(unsigned int stream) { void SctpTransport::closeStream(unsigned int stream) {
send(make_message(0, Message::Reset, uint16_t(stream))); send(make_message(0, Message::Reset, to_uint16(stream)));
} }
void SctpTransport::incoming(message_ptr message) { void SctpTransport::incoming(message_ptr message) {
@ -374,9 +432,6 @@ void SctpTransport::incoming(message_ptr message) {
PLOG_VERBOSE << "Incoming size=" << message->size(); PLOG_VERBOSE << "Incoming size=" << message->size();
// TODO: There seems to be a possible data race between usrsctp_sendv() and usrsctp_conninput()
// As a mitigation, lock the send mutex before calling usrsctp_conninput()
std::lock_guard lock(mSendMutex);
usrsctp_conninput(this, message->data(), message->size(), 0); usrsctp_conninput(this, message->data(), message->size(), 0);
} }
@ -458,7 +513,7 @@ bool SctpTransport::trySendQueue() {
if (!trySendMessage(message)) if (!trySendMessage(message))
return false; return false;
mSendQueue.pop(); mSendQueue.pop();
updateBufferedAmount(uint16_t(message->stream), -long(message_size_func(message))); updateBufferedAmount(to_uint16(message->stream), -ptrdiff_t(message_size_func(message)));
} }
return true; return true;
} }
@ -511,12 +566,12 @@ bool SctpTransport::trySendMessage(message_ptr message) {
case Reliability::Type::Rexmit: case Reliability::Type::Rexmit:
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
spa.sendv_prinfo.pr_value = uint32_t(std::get<int>(reliability.rexmit)); spa.sendv_prinfo.pr_value = to_uint32(std::get<int>(reliability.rexmit));
break; break;
case Reliability::Type::Timed: case Reliability::Type::Timed:
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL; spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
spa.sendv_prinfo.pr_value = uint32_t(std::get<milliseconds>(reliability.rexmit).count()); spa.sendv_prinfo.pr_value = to_uint32(std::get<milliseconds>(reliability.rexmit).count());
break; break;
default: default:
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE; spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
@ -548,10 +603,10 @@ bool SctpTransport::trySendMessage(message_ptr message) {
return true; return true;
} }
void SctpTransport::updateBufferedAmount(uint16_t streamId, long delta) { void SctpTransport::updateBufferedAmount(uint16_t streamId, ptrdiff_t delta) {
// Requires mSendMutex to be locked // Requires mSendMutex to be locked
auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first; auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first;
size_t amount = size_t(std::max(long(it->second) + delta, long(0))); size_t amount = size_t(std::max(ptrdiff_t(it->second) + delta, ptrdiff_t(0)));
if (amount == 0) if (amount == 0)
mBufferedAmount.erase(it); mBufferedAmount.erase(it);
else else
@ -809,11 +864,8 @@ optional<milliseconds> SctpTransport::rtt() {
void SctpTransport::UpcallCallback(struct socket *, void *arg, int /* flags */) { void SctpTransport::UpcallCallback(struct socket *, void *arg, int /* flags */) {
auto *transport = static_cast<SctpTransport *>(arg); auto *transport = static_cast<SctpTransport *>(arg);
std::shared_lock lock(InstancesMutex); if(auto lock = Instances->lock(transport))
if (Instances.find(transport) == Instances.end()) transport->handleUpcall();
return;
transport->handleUpcall();
} }
int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) { int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) {
@ -821,11 +873,10 @@ int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos,
// Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket // Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket
// https://github.com/sctplab/usrsctp/issues/405 // https://github.com/sctplab/usrsctp/issues/405
std::shared_lock lock(InstancesMutex); if(auto lock = Instances->lock(transport))
if (Instances.find(transport) == Instances.end()) return transport->handleWrite(static_cast<byte *>(data), len, tos, set_df);
else
return -1; return -1;
return transport->handleWrite(static_cast<byte *>(data), len, tos, set_df);
} }
} // namespace rtc::impl } // namespace rtc::impl

View File

@ -39,6 +39,7 @@ namespace rtc::impl {
class SctpTransport final : public Transport { class SctpTransport final : public Transport {
public: public:
static void Init(); static void Init();
static void SetSettings(const SctpSettings &s);
static void Cleanup(); static void Cleanup();
using amount_callback = std::function<void(uint16_t streamId, size_t amount)>; using amount_callback = std::function<void(uint16_t streamId, size_t amount)>;
@ -83,7 +84,7 @@ private:
void doFlush(); void doFlush();
bool trySendQueue(); bool trySendQueue();
bool trySendMessage(message_ptr message); bool trySendMessage(message_ptr message);
void updateBufferedAmount(uint16_t streamId, long delta); void updateBufferedAmount(uint16_t streamId, ptrdiff_t delta);
void triggerBufferedAmount(uint16_t streamId, size_t amount); void triggerBufferedAmount(uint16_t streamId, size_t amount);
void sendReset(uint16_t streamId); void sendReset(uint16_t streamId);
@ -119,8 +120,8 @@ private:
static void UpcallCallback(struct socket *sock, void *arg, int flags); static void UpcallCallback(struct socket *sock, void *arg, int flags);
static int WriteCallback(void *sctp_ptr, void *data, size_t len, uint8_t tos, uint8_t set_df); static int WriteCallback(void *sctp_ptr, void *data, size_t len, uint8_t tos, uint8_t set_df);
static std::unordered_set<SctpTransport *> Instances; class InstancesSet;
static std::shared_mutex InstancesMutex; static InstancesSet *Instances;
}; };
} // namespace rtc::impl } // namespace rtc::impl

View File

@ -17,7 +17,7 @@
*/ */
#include "tcptransport.hpp" #include "tcptransport.hpp"
#include "globals.hpp" #include "internals.hpp"
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET

View File

@ -21,6 +21,7 @@
#include "common.hpp" #include "common.hpp"
#include "init.hpp" #include "init.hpp"
#include "internals.hpp"
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>

View File

@ -18,6 +18,8 @@
#include "tls.hpp" #include "tls.hpp"
#include "internals.hpp"
#if USE_GNUTLS #if USE_GNUTLS
namespace rtc::gnutls { namespace rtc::gnutls {

View File

@ -17,7 +17,7 @@
*/ */
#include "track.hpp" #include "track.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "logcounter.hpp" #include "logcounter.hpp"
#include "peerconnection.hpp" #include "peerconnection.hpp"

View File

@ -20,6 +20,7 @@
#define RTC_IMPL_TRANSPORT_H #define RTC_IMPL_TRANSPORT_H
#include "common.hpp" #include "common.hpp"
#include "internals.hpp"
#include "message.hpp" #include "message.hpp"
#include <atomic> #include <atomic>

View File

@ -19,7 +19,7 @@
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
#include "websocket.hpp" #include "websocket.hpp"
#include "globals.hpp" #include "internals.hpp"
#include "common.hpp" #include "common.hpp"
#include "threadpool.hpp" #include "threadpool.hpp"

View File

@ -1,47 +0,0 @@
/**
* Copyright (c) 2019-2020 Paul-Louis Ageneau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.hpp"
#include "plog/Appenders/ColorConsoleAppender.h"
#include "plog/Formatters/TxtFormatter.h"
#include "plog/Init.h"
#include "plog/Log.h"
#include "plog/Logger.h"
#include <mutex>
namespace rtc {
void InitLogger(LogLevel level) { InitLogger(static_cast<plog::Severity>(level)); }
void InitLogger(plog::Severity severity, plog::IAppender *appender) {
static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
static plog::Logger<0> *logger = nullptr;
static std::mutex mutex;
std::lock_guard lock(mutex);
if (!logger) {
logger = &plog::init(severity, appender ? appender : &consoleAppender);
PLOG_DEBUG << "Logger initialized";
} else {
logger->setMaxSeverity(severity);
if (appender)
logger->addAppender(appender);
}
}
} // namespace rtc

View File

@ -1,24 +1,29 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "mediachainablehandler.hpp" #include "mediachainablehandler.hpp"
#include "impl/internals.hpp"
#include <cassert>
namespace rtc { namespace rtc {
MediaChainableHandler::MediaChainableHandler(shared_ptr<MediaHandlerRootElement> root): MediaHandler(), root(root), leaf(root) { } MediaChainableHandler::MediaChainableHandler(shared_ptr<MediaHandlerRootElement> root): MediaHandler(), root(root), leaf(root) { }

View File

@ -1,24 +1,29 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "mediahandlerelement.hpp" #include "mediahandlerelement.hpp"
#include "impl/internals.hpp"
#include <cassert>
namespace rtc { namespace rtc {
ChainedMessagesProduct make_chained_messages_product() { ChainedMessagesProduct make_chained_messages_product() {

View File

@ -1,18 +1,19 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA

View File

@ -1,25 +1,26 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "nalunit.hpp" #include "nalunit.hpp"
#include "globals.hpp"
#include "impl/internals.hpp"
#include <cmath> #include <cmath>

View File

@ -1,19 +1,19 @@
/* /**
* libdatachannel client example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA

View File

@ -1,25 +1,27 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "opusrtppacketizer.hpp" #include "opusrtppacketizer.hpp"
#include <cassert>
namespace rtc { namespace rtc {
OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig) OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)

View File

@ -24,6 +24,7 @@
#include "impl/certificate.hpp" #include "impl/certificate.hpp"
#include "impl/dtlstransport.hpp" #include "impl/dtlstransport.hpp"
#include "impl/icetransport.hpp" #include "impl/icetransport.hpp"
#include "impl/internals.hpp"
#include "impl/peerconnection.hpp" #include "impl/peerconnection.hpp"
#include "impl/processor.hpp" #include "impl/processor.hpp"
#include "impl/sctptransport.hpp" #include "impl/sctptransport.hpp"
@ -266,7 +267,7 @@ shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, DataChan
void PeerConnection::onDataChannel( void PeerConnection::onDataChannel(
std::function<void(shared_ptr<DataChannel> dataChannel)> callback) { std::function<void(shared_ptr<DataChannel> dataChannel)> callback) {
impl()->dataChannelCallback = callback; impl()->dataChannelCallback = callback;
impl()->triggerDataChannel(); // trigger pending DataChannels impl()->flushPendingDataChannels();
} }
std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description) { std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description) {
@ -281,7 +282,7 @@ std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description)
void PeerConnection::onTrack(std::function<void(std::shared_ptr<Track>)> callback) { void PeerConnection::onTrack(std::function<void(std::shared_ptr<Track>)> callback) {
impl()->trackCallback = callback; impl()->trackCallback = callback;
impl()->triggerTrack(); // trigger pending tracks impl()->flushPendingTracks();
} }
void PeerConnection::onLocalDescription(std::function<void(Description description)> callback) { void PeerConnection::onLocalDescription(std::function<void(Description description)> callback) {

View File

@ -1,24 +1,29 @@
/** /**
* libdatachannel streamer example * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "rtcpnackresponder.hpp" #include "rtcpnackresponder.hpp"
#include "impl/internals.hpp"
#include <cassert>
namespace rtc { namespace rtc {
RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next) RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next)
@ -80,7 +85,7 @@ ChainedIncomingControlProduct RtcpNackResponder::processIncomingControlMessage(m
if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) { if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) {
continue; continue;
} }
auto fieldsCount = nack->getSeqNoCount(); auto fieldsCount = nack->getSeqNoCount();
std::vector<uint16_t> missingSequenceNumbers{}; std::vector<uint16_t> missingSequenceNumbers{};

View File

@ -97,7 +97,7 @@ void RtcpReceivingSession::requestBitrate(unsigned int newBitrate) {
} }
void RtcpReceivingSession::pushREMB(unsigned int bitrate) { void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
message_ptr msg = make_message(RTCP_REMB::sizeWithSSRCs(1), Message::Type::Control); message_ptr msg = make_message(RTCP_REMB::SizeWithSSRCs(1), Message::Type::Control);
auto remb = reinterpret_cast<RTCP_REMB *>(msg->data()); auto remb = reinterpret_cast<RTCP_REMB *>(msg->data());
remb->preparePacket(mSsrc, 1, bitrate); remb->preparePacket(mSsrc, 1, bitrate);
remb->setSsrc(0, mSsrc); remb->setSsrc(0, mSsrc);
@ -106,7 +106,7 @@ void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
} }
void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) { void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) {
auto msg = make_message(RTCP_RR::sizeWithReportBlocks(1), Message::Type::Control); auto msg = make_message(RTCP_RR::SizeWithReportBlocks(1), Message::Type::Control);
auto rr = reinterpret_cast<RTCP_RR *>(msg->data()); auto rr = reinterpret_cast<RTCP_RR *>(msg->data());
rr->preparePacket(mSsrc, 1); rr->preparePacket(mSsrc, 1);
rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS, rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS,
@ -132,7 +132,7 @@ bool RtcpReceivingSession::requestKeyframe() {
} }
void RtcpReceivingSession::pushPLI() { void RtcpReceivingSession::pushPLI() {
auto msg = make_message(RTCP_PLI::size(), Message::Type::Control); auto msg = make_message(RTCP_PLI::Size(), Message::Type::Control);
auto *pli = reinterpret_cast<RTCP_PLI *>(msg->data()); auto *pli = reinterpret_cast<RTCP_PLI *>(msg->data());
pli->preparePacket(mSsrc); pli->preparePacket(mSsrc);
send(msg); send(msg);

View File

@ -1,24 +1,28 @@
/** /**
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "rtcpsrreporter.hpp" #include "rtcpsrreporter.hpp"
#include <cmath>
#include <cassert>
namespace rtc { namespace rtc {
ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) { ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) {
@ -60,8 +64,8 @@ uint64_t RtcpSrReporter::secondsToNTP(double seconds) {
void RtcpSrReporter::setNeedsToReport() { needsToReport = true; } void RtcpSrReporter::setNeedsToReport() { needsToReport = true; }
message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) { message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) {
auto srSize = RTCP_SR::size(0); auto srSize = RTCP_SR::Size(0);
auto msg = make_message(srSize + RTCP_SDES::size({{uint8_t(rtpConfig->cname.size())}}), auto msg = make_message(srSize + RTCP_SDES::Size({{uint8_t(rtpConfig->cname.size())}}),
Message::Type::Control); Message::Type::Control);
auto sr = reinterpret_cast<RTCP_SR *>(msg->data()); auto sr = reinterpret_cast<RTCP_SR *>(msg->data());
auto timestamp_s = rtpConfig->timestampToSeconds(timestamp); auto timestamp_s = rtpConfig->timestampToSeconds(timestamp);

600
src/rtp.cpp Normal file
View File

@ -0,0 +1,600 @@
/**
* Copyright (c) 2020 Staz Modrzynski
* Copyright (c) 2020 Paul-Louis Ageneau
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "rtp.hpp"
#include "impl/internals.hpp"
#include <cmath>
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#ifndef htonll
#define htonll(x) \
((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32)))
#endif
#ifndef ntohll
#define ntohll(x) htonll(x)
#endif
namespace rtc {
uint8_t RTP::version() const { return _first >> 6; }
bool RTP::padding() const { return (_first >> 5) & 0x01; }
bool RTP::extension() const { return (_first >> 4) & 0x01; }
uint8_t RTP::csrcCount() const { return _first & 0x0F; }
uint8_t RTP::marker() const { return _payloadType & 0b10000000; }
uint8_t RTP::payloadType() const { return _payloadType & 0b01111111; }
uint16_t RTP::seqNumber() const { return ntohs(_seqNumber); }
uint32_t RTP::timestamp() const { return ntohl(_timestamp); }
uint32_t RTP::ssrc() const { return ntohl(_ssrc); }
size_t RTP::getSize() const {
return reinterpret_cast<const char *>(&_csrc) - reinterpret_cast<const char *>(this) +
sizeof(SSRC) * csrcCount();
}
const char *RTP::getBody() const {
return reinterpret_cast<const char *>(&_csrc) + sizeof(SSRC) * csrcCount();
}
char *RTP::getBody() { return reinterpret_cast<char *>(&_csrc) + sizeof(SSRC) * csrcCount(); }
void RTP::preparePacket() { _first |= (1 << 7); }
void RTP::setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); }
void RTP::setPayloadType(uint8_t newPayloadType) {
_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
}
void RTP::setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); }
void RTP::setMarker(bool marker) { _payloadType = (_payloadType & 0x7F) | (marker << 7); };
void RTP::setTimestamp(uint32_t i) { _timestamp = htonl(i); }
void RTP::log() const {
PLOG_VERBOSE << "RTP V: " << (int)version() << " P: " << (padding() ? "P" : " ")
<< " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount()
<< " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType()
<< " SEQNO: " << seqNumber() << " TS: " << timestamp();
}
SSRC RTCP_ReportBlock::getSSRC() const { return ntohl(_ssrc); }
void RTCP_ReportBlock::preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost,
[[maybe_unused]] unsigned int totalPackets,
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);
// Middle 32 bits of NTP Timestamp
// _lastReport = lastSR_NTP >> 16u;
setNTPOfSR(uint64_t(lastSR_NTP));
setDelaySinceSR(uint32_t(lastSR_DELAY));
// The delay, expressed in units of 1/65536 seconds
// _delaySinceLastReport = lastSR_DELAY;
}
void RTCP_ReportBlock::setSSRC(SSRC in_ssrc) { _ssrc = htonl(in_ssrc); }
void RTCP_ReportBlock::setPacketsLost([[maybe_unused]] unsigned int packetsLost,
[[maybe_unused]] unsigned int totalPackets) {
// TODO Implement loss percentages.
_fractionLostAndPacketsLost = 0;
}
unsigned int RTCP_ReportBlock::getLossPercentage() const {
// TODO Implement loss percentages.
return 0;
}
unsigned int RTCP_ReportBlock::getPacketLostCount() const {
// TODO Implement total packets lost.
return 0;
}
uint16_t RTCP_ReportBlock::seqNoCycles() const { return ntohs(_seqNoCycles); }
uint16_t RTCP_ReportBlock::highestSeqNo() const { return ntohs(_highestSeqNo); }
uint32_t RTCP_ReportBlock::jitter() const { return ntohl(_jitter); }
uint32_t RTCP_ReportBlock::delaySinceSR() const { return ntohl(_delaySinceLastReport); }
void RTCP_ReportBlock::setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) {
_highestSeqNo = htons(highestSeqNo);
_seqNoCycles = htons(seqNoCycles);
}
void RTCP_ReportBlock::setJitter(uint32_t jitter) { _jitter = htonl(jitter); }
void RTCP_ReportBlock::setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); }
uint32_t RTCP_ReportBlock::getNTPOfSR() const { return ntohl(_lastReport) << 16u; }
void RTCP_ReportBlock::setDelaySinceSR(uint32_t sr) {
// The delay, expressed in units of 1/65536 seconds
_delaySinceLastReport = htonl(sr);
}
void RTCP_ReportBlock::log() const {
PLOG_VERBOSE << "RTCP report block: "
<< "ssrc="
<< ntohl(_ssrc)
// TODO: Implement these reports
// << ", fractionLost=" << fractionLost
// << ", packetsLost=" << packetsLost
<< ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles()
<< ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR()
<< ", lastSRDelay=" << delaySinceSR();
}
uint8_t RTCP_HEADER::version() const { return _first >> 6; }
bool RTCP_HEADER::padding() const { return (_first >> 5) & 0x01; }
uint8_t RTCP_HEADER::reportCount() const { return _first & 0x0F; }
uint8_t RTCP_HEADER::payloadType() const { return _payloadType; }
uint16_t RTCP_HEADER::length() const { return ntohs(_length); }
size_t RTCP_HEADER::lengthInBytes() const { return (1 + length()) * 4; }
void RTCP_HEADER::setPayloadType(uint8_t type) { _payloadType = type; }
void RTCP_HEADER::setReportCount(uint8_t count) {
_first = (_first & 0b11100000u) | (count & 0b00011111u);
}
void RTCP_HEADER::setLength(uint16_t length) { _length = htons(length); }
void RTCP_HEADER::prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) {
_first = 0b10000000; // version 2, no padding
setReportCount(reportCount);
setPayloadType(payloadType);
setLength(length);
}
void RTCP_HEADER::log() const {
PLOG_VERBOSE << "RTCP header: "
<< "version=" << unsigned(version()) << ", padding=" << padding()
<< ", reportCount=" << unsigned(reportCount())
<< ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
}
SSRC RTCP_FB_HEADER::packetSenderSSRC() const { return ntohl(_packetSender); }
SSRC RTCP_FB_HEADER::mediaSourceSSRC() const { return ntohl(_mediaSource); }
void RTCP_FB_HEADER::setPacketSenderSSRC(SSRC ssrc) { _packetSender = htonl(ssrc); }
void RTCP_FB_HEADER::setMediaSourceSSRC(SSRC ssrc) { _mediaSource = htonl(ssrc); }
void RTCP_FB_HEADER::log() const {
header.log();
PLOG_VERBOSE << "FB: "
<< " packet sender: " << packetSenderSSRC()
<< " media source: " << mediaSourceSSRC();
}
unsigned int RTCP_SR::Size(unsigned int reportCount) {
return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock);
}
void RTCP_SR::preparePacket(SSRC senderSSRC, uint8_t reportCount) {
unsigned int length = ((sizeof(header) + 24 + reportCount * sizeof(RTCP_ReportBlock)) / 4) - 1;
header.prepareHeader(200, reportCount, uint16_t(length));
this->_senderSSRC = htonl(senderSSRC);
}
const RTCP_ReportBlock *RTCP_SR::getReportBlock(int num) const { return &_reportBlocks + num; }
RTCP_ReportBlock *RTCP_SR::getReportBlock(int num) { return &_reportBlocks + num; }
size_t RTCP_SR::getSize() const {
// "length" in packet is one less than the number of 32 bit words in the packet.
return sizeof(uint32_t) * (1 + size_t(header.length()));
}
uint64_t RTCP_SR::ntpTimestamp() const { return ntohll(_ntpTimestamp); }
uint32_t RTCP_SR::rtpTimestamp() const { return ntohl(_rtpTimestamp); }
uint32_t RTCP_SR::packetCount() const { return ntohl(_packetCount); }
uint32_t RTCP_SR::octetCount() const { return ntohl(_octetCount); }
uint32_t RTCP_SR::senderSSRC() const { return ntohl(_senderSSRC); }
void RTCP_SR::setNtpTimestamp(uint64_t ts) { _ntpTimestamp = htonll(ts); }
void RTCP_SR::setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); }
void RTCP_SR::setOctetCount(uint32_t ts) { _octetCount = htonl(ts); }
void RTCP_SR::setPacketCount(uint32_t ts) { _packetCount = htonl(ts); }
void RTCP_SR::log() const {
header.log();
PLOG_VERBOSE << "RTCP SR: "
<< " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp()
<< ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount()
<< ", octetCount=" << octetCount();
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
getReportBlock(i)->log();
}
}
unsigned int RTCP_SDES_ITEM::Size(uint8_t textLength) { return textLength + 2; }
std::string RTCP_SDES_ITEM::text() const { return std::string(_text, _length); }
void RTCP_SDES_ITEM::setText(std::string text) {
if (text.size() > 0xFF)
throw std::invalid_argument("text is too long");
_length = uint8_t(text.size());
memcpy(_text, text.data(), text.size());
}
uint8_t RTCP_SDES_ITEM::length() const { return _length; }
unsigned int RTCP_SDES_CHUNK::Size(const std::vector<uint8_t> textLengths) {
unsigned int itemsSize = 0;
for (auto length : textLengths) {
itemsSize += RTCP_SDES_ITEM::Size(length);
}
auto nullTerminatedItemsSize = itemsSize + 1;
auto words = uint8_t(std::ceil(double(nullTerminatedItemsSize) / 4)) + 1;
return words * 4;
}
SSRC RTCP_SDES_CHUNK::ssrc() const { return ntohl(_ssrc); }
void RTCP_SDES_CHUNK::setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); }
const RTCP_SDES_ITEM *RTCP_SDES_CHUNK::getItem(int num) const {
auto base = &_items;
while (num-- > 0) {
auto itemSize = RTCP_SDES_ITEM::Size(base->length());
base = reinterpret_cast<const RTCP_SDES_ITEM *>(reinterpret_cast<const uint8_t *>(base) +
itemSize);
}
return reinterpret_cast<const RTCP_SDES_ITEM *>(base);
}
RTCP_SDES_ITEM *RTCP_SDES_CHUNK::getItem(int num) {
auto base = &_items;
while (num-- > 0) {
auto itemSize = RTCP_SDES_ITEM::Size(base->length());
base = reinterpret_cast<RTCP_SDES_ITEM *>(reinterpret_cast<uint8_t *>(base) + itemSize);
}
return reinterpret_cast<RTCP_SDES_ITEM *>(base);
}
unsigned int RTCP_SDES_CHUNK::getSize() const {
std::vector<uint8_t> textLengths{};
unsigned int i = 0;
auto item = getItem(i);
while (item->type != 0) {
textLengths.push_back(item->length());
item = getItem(++i);
}
return Size(textLengths);
}
long RTCP_SDES_CHUNK::safelyCountChunkSize(size_t maxChunkSize) const {
if (maxChunkSize < RTCP_SDES_CHUNK::Size({})) {
// chunk is truncated
return -1;
}
size_t size = sizeof(SSRC);
unsigned int i = 0;
// We can always access first 4 bytes of first item (in case of no items there will be 4
// null bytes)
auto item = getItem(i);
std::vector<uint8_t> textsLength{};
while (item->type != 0) {
if (size + RTCP_SDES_ITEM::Size(0) > maxChunkSize) {
// item is too short
return -1;
}
auto itemLength = item->length();
if (size + RTCP_SDES_ITEM::Size(itemLength) >= maxChunkSize) {
// item is too large (it can't be equal to chunk size because after item there
// must be 1-4 null bytes as padding)
return -1;
}
textsLength.push_back(itemLength);
// safely to access next item
item = getItem(++i);
}
auto realSize = RTCP_SDES_CHUNK::Size(textsLength);
if (realSize > maxChunkSize) {
// Chunk is too large
return -1;
}
return realSize;
}
unsigned int RTCP_SDES::Size(const std::vector<std::vector<uint8_t>> lengths) {
unsigned int chunks_size = 0;
for (auto length : lengths)
chunks_size += RTCP_SDES_CHUNK::Size(length);
return 4 + chunks_size;
}
bool RTCP_SDES::isValid() const {
auto chunksSize = header.lengthInBytes() - sizeof(header);
if (chunksSize == 0) {
return true;
}
// there is at least one chunk
unsigned int i = 0;
unsigned int size = 0;
while (size < chunksSize) {
if (chunksSize < size + RTCP_SDES_CHUNK::Size({})) {
// chunk is truncated
return false;
}
auto chunk = getChunk(i++);
auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size);
if (chunkSize < 0) {
// chunk is invalid
return false;
}
size += chunkSize;
}
return size == chunksSize;
}
unsigned int RTCP_SDES::chunksCount() const {
if (!isValid()) {
return 0;
}
uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header);
unsigned int size = 0;
unsigned int i = 0;
while (size < chunksSize) {
size += getChunk(i++)->getSize();
}
return i;
}
const RTCP_SDES_CHUNK *RTCP_SDES::getChunk(int num) const {
auto base = &_chunks;
while (num-- > 0) {
auto chunkSize = base->getSize();
base = reinterpret_cast<const RTCP_SDES_CHUNK *>(reinterpret_cast<const uint8_t *>(base) +
chunkSize);
}
return reinterpret_cast<const RTCP_SDES_CHUNK *>(base);
}
RTCP_SDES_CHUNK *RTCP_SDES::getChunk(int num) {
auto base = &_chunks;
while (num-- > 0) {
auto chunkSize = base->getSize();
base = reinterpret_cast<RTCP_SDES_CHUNK *>(reinterpret_cast<uint8_t *>(base) + chunkSize);
}
return reinterpret_cast<RTCP_SDES_CHUNK *>(base);
}
void RTCP_SDES::preparePacket(uint8_t chunkCount) {
unsigned int chunkSize = 0;
for (uint8_t i = 0; i < chunkCount; i++) {
auto chunk = getChunk(i);
chunkSize += chunk->getSize();
}
uint16_t length = uint16_t((sizeof(header) + chunkSize) / 4 - 1);
header.prepareHeader(202, chunkCount, length);
}
const RTCP_ReportBlock *RTCP_RR::getReportBlock(int num) const { return &_reportBlocks + num; }
RTCP_ReportBlock *RTCP_RR::getReportBlock(int num) { return &_reportBlocks + num; }
size_t RTCP_RR::SizeWithReportBlocks(uint8_t reportCount) {
return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock);
}
SSRC RTCP_RR::senderSSRC() const { return ntohl(_senderSSRC); }
bool RTCP_RR::isSenderReport() { return header.payloadType() == 200; }
bool RTCP_RR::isReceiverReport() { return header.payloadType() == 201; }
size_t RTCP_RR::getSize() const {
// "length" in packet is one less than the number of 32 bit words in the packet.
return sizeof(uint32_t) * (1 + size_t(header.length()));
}
void RTCP_RR::preparePacket(SSRC senderSSRC, uint8_t reportCount) {
// "length" in packet is one less than the number of 32 bit words in the packet.
size_t length = (SizeWithReportBlocks(reportCount) / 4) - 1;
header.prepareHeader(201, reportCount, uint16_t(length));
this->_senderSSRC = htonl(senderSSRC);
}
void RTCP_RR::setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); }
void RTCP_RR::log() const {
header.log();
PLOG_VERBOSE << "RTCP RR: "
<< " SSRC=" << ntohl(_senderSSRC);
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
getReportBlock(i)->log();
}
}
size_t RTCP_REMB::SizeWithSSRCs(int count) {
return sizeof(RTCP_REMB) + (count - 1) * sizeof(SSRC);
}
unsigned int RTCP_REMB::getSize() const {
// "length" in packet is one less than the number of 32 bit words in the packet.
return sizeof(uint32_t) * (1 + header.header.length());
}
void RTCP_REMB::preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) {
// Report Count becomes the format here.
header.header.prepareHeader(206, 15, 0);
// Always zero.
header.setMediaSourceSSRC(0);
header.setPacketSenderSSRC(senderSSRC);
_id[0] = 'R';
_id[1] = 'E';
_id[2] = 'M';
_id[3] = 'B';
setBitrate(numSSRC, in_bitrate);
}
void RTCP_REMB::setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
unsigned int exp = 0;
while (in_bitrate > pow(2, 18) - 1) {
exp++;
in_bitrate /= 2;
}
// "length" in packet is one less than the number of 32 bit words in the packet.
header.header.setLength(
uint16_t((offsetof(RTCP_REMB, _ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
_bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate);
}
void RTCP_REMB::setSsrc(int iterator, SSRC newSssrc) { _ssrc[iterator] = htonl(newSssrc); }
unsigned int RTCP_PLI::Size() { return sizeof(RTCP_FB_HEADER); }
void RTCP_PLI::preparePacket(SSRC messageSSRC) {
header.header.prepareHeader(206, 1, 2);
header.setPacketSenderSSRC(messageSSRC);
header.setMediaSourceSSRC(messageSSRC);
}
void RTCP_PLI::log() const { header.log(); }
unsigned int RTCP_FIR::Size() { return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART); }
void RTCP_FIR::preparePacket(SSRC messageSSRC, uint8_t seqNo) {
header.header.prepareHeader(206, 4, 2 + 2 * 1);
header.setPacketSenderSSRC(messageSSRC);
header.setMediaSourceSSRC(messageSSRC);
parts[0].ssrc = htonl(messageSSRC);
parts[0].seqNo = seqNo;
}
void RTCP_FIR::log() const { header.log(); }
uint16_t RTCP_NACK_PART::pid() { return ntohs(_pid); }
uint16_t RTCP_NACK_PART::blp() { return ntohs(_blp); }
void RTCP_NACK_PART::setPid(uint16_t pid) { _pid = htons(pid); }
void RTCP_NACK_PART::setBlp(uint16_t blp) { _blp = htons(blp); }
std::vector<uint16_t> RTCP_NACK_PART::getSequenceNumbers() {
std::vector<uint16_t> result{};
result.reserve(17);
uint16_t p = pid();
result.push_back(p);
uint16_t bitmask = blp();
uint16_t i = p + 1;
while (bitmask > 0) {
if (bitmask & 0x1) {
result.push_back(i);
}
i += 1;
bitmask >>= 1;
}
return result;
}
unsigned int RTCP_NACK::Size(unsigned int discreteSeqNoCount) {
return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount;
}
unsigned int RTCP_NACK::getSeqNoCount() { return header.header.length() - 2; }
void RTCP_NACK::preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount));
header.setMediaSourceSSRC(ssrc);
header.setPacketSenderSSRC(ssrc);
}
bool RTCP_NACK::addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket) {
if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) {
parts[*fciCount].setPid(missingPacket);
parts[*fciCount].setBlp(0);
*fciPID = missingPacket;
(*fciCount)++;
return true;
} else {
// TODO SPEED!
uint16_t blp = parts[(*fciCount) - 1].blp();
uint16_t newBit = uint16_t(1u << (missingPacket - (1 + *fciPID)));
parts[(*fciCount) - 1].setBlp(blp | newBit);
return false;
}
}
uint16_t RTP_RTX::getOriginalSeqNo() const { return ntohs(*(uint16_t *)(header.getBody())); }
const char *RTP_RTX::getBody() const { return header.getBody() + sizeof(uint16_t); }
char *RTP_RTX::getBody() { return header.getBody() + sizeof(uint16_t); }
size_t RTP_RTX::getBodySize(size_t totalSize) const {
return totalSize - (getBody() - reinterpret_cast<const char *>(this));
}
size_t RTP_RTX::getSize() const { return header.getSize() + sizeof(uint16_t); }
size_t RTP_RTX::normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) {
header.setSeqNumber(getOriginalSeqNo());
header.setSsrc(originalSSRC);
header.setPayloadType(originalPayloadType);
// TODO, the -12 is the size of the header (which is variable!)
memmove(header.getBody(), getBody(), totalSize - getSize());
return totalSize - 2;
}
size_t RTP_RTX::copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) {
memmove((char *)dest, (char *)this, header.getSize());
dest->setSeqNumber(getOriginalSeqNo());
dest->setPayloadType(originalPayloadType);
memmove(dest->getBody(), getBody(), getBodySize(totalSize));
return totalSize;
}
}; // namespace rtc

View File

@ -1,25 +1,27 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "rtppacketizationconfig.hpp" #include "rtppacketizationconfig.hpp"
#include <cassert>
namespace rtc { namespace rtc {
RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType, RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType,

View File

@ -1,25 +1,27 @@
/* /**
* libdatachannel streamer example
* Copyright (c) 2020 Filip Klembara (in2core) * Copyright (c) 2020 Filip Klembara (in2core)
* *
* This program is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU Lesser General Public
* as published by the Free Software Foundation; either version 2 * License as published by the Free Software Foundation; either
* of the License, or (at your option) any later version. * version 2.1 of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; If not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
#include "rtppacketizer.hpp" #include "rtppacketizer.hpp"
#include <cstring>
namespace rtc { namespace rtc {
RtpPacketizer::RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig) RtpPacketizer::RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
@ -37,7 +39,7 @@ binary_ptr RtpPacketizer::packetize(shared_ptr<binary> payload, bool setMark) {
rtp->setMarker(true); rtp->setMarker(true);
} }
rtp->preparePacket(); rtp->preparePacket();
memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size()); std::memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size());
return msg; return msg;
} }

View File

@ -17,8 +17,8 @@
*/ */
#include "track.hpp" #include "track.hpp"
#include "globals.hpp"
#include "impl/internals.hpp"
#include "impl/track.hpp" #include "impl/track.hpp"
namespace rtc { namespace rtc {
@ -46,9 +46,7 @@ bool Track::isOpen(void) const { return impl()->isOpen(); }
bool Track::isClosed(void) const { return impl()->isClosed(); } bool Track::isClosed(void) const { return impl()->isClosed(); }
size_t Track::maxMessageSize() const { size_t Track::maxMessageSize() const { return impl()->maxMessageSize(); }
return impl()->maxMessageSize();
}
void Track::setMediaHandler(shared_ptr<MediaHandler> handler) { void Track::setMediaHandler(shared_ptr<MediaHandler> handler) {
impl()->setMediaHandler(std::move(handler)); impl()->setMediaHandler(std::move(handler));

View File

@ -19,10 +19,10 @@
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
#include "websocket.hpp" #include "websocket.hpp"
#include "globals.hpp"
#include "common.hpp" #include "common.hpp"
#include "impl/websocket.hpp" #include "impl/websocket.hpp"
#include "impl/internals.hpp"
#include <regex> #include <regex>

View File

@ -121,12 +121,11 @@ size_t benchmark(milliseconds duration) {
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl; std::cout << "Send failed: " << e.what() << std::endl;
} }
// When sent data is buffered in the DataChannel,
// wait for onBufferedAmountLow callback to continue
}); });
// When sent data is buffered in the DataChannel,
// wait for onBufferedAmountLow callback to continue
dc1->onBufferedAmountLow([wdc1 = make_weak_ptr(dc1), &messageData]() { dc1->onBufferedAmountLow([wdc1 = make_weak_ptr(dc1), &messageData]() {
auto dc1 = wdc1.lock(); auto dc1 = wdc1.lock();
if (!dc1) if (!dc1)

View File

@ -137,11 +137,11 @@ static void RTC_API dataChannelCallback(int pc, int dc, void *ptr) {
return; return;
} }
rtcSetOpenCallback(dc, openCallback);
rtcSetClosedCallback(dc, closedCallback); rtcSetClosedCallback(dc, closedCallback);
rtcSetMessageCallback(dc, messageCallback); rtcSetMessageCallback(dc, messageCallback);
peer->dc = dc; peer->dc = dc;
peer->connected = true;
const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2"; const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string

View File

@ -83,7 +83,7 @@ static void RTC_API closedCallback(int id, void *ptr) {
static void RTC_API trackCallback(int pc, int tr, void *ptr) { static void RTC_API trackCallback(int pc, int tr, void *ptr) {
Peer *peer = (Peer *)ptr; Peer *peer = (Peer *)ptr;
peer->tr = tr; peer->tr = tr;
peer->connected = true; rtcSetOpenCallback(tr, openCallback);
rtcSetClosedCallback(tr, closedCallback); rtcSetClosedCallback(tr, closedCallback);
char buffer[1024]; char buffer[1024];

View File

@ -24,6 +24,8 @@
#include <memory> #include <memory>
#include <thread> #include <thread>
#define CUSTOM_MAX_MESSAGE_SIZE 1048576
using namespace rtc; using namespace rtc;
using namespace std; using namespace std;
@ -39,7 +41,7 @@ void test_connectivity() {
// Custom MTU example // Custom MTU example
config1.mtu = 1500; config1.mtu = 1500;
// Custom max message size // Custom max message size
config1.maxMessageSize = 1048576; config1.maxMessageSize = CUSTOM_MAX_MESSAGE_SIZE;
PeerConnection pc1(config1); PeerConnection pc1(config1);
@ -50,7 +52,7 @@ void test_connectivity() {
// Custom MTU example // Custom MTU example
config2.mtu = 1500; config2.mtu = 1500;
// Custom max message size // Custom max message size
config2.maxMessageSize = 1048576; config2.maxMessageSize = CUSTOM_MAX_MESSAGE_SIZE;
// Port range example // Port range example
config2.portRangeBegin = 5000; config2.portRangeBegin = 5000;
config2.portRangeEnd = 6000; config2.portRangeEnd = 6000;
@ -105,26 +107,29 @@ void test_connectivity() {
return; return;
} }
dc->onOpen([wdc = make_weak_ptr(dc)]() {
if (auto dc = wdc.lock())
dc->send("Hello from 2");
});
dc->onMessage([](variant<binary, string> message) { dc->onMessage([](variant<binary, string> message) {
if (holds_alternative<string>(message)) { if (holds_alternative<string>(message)) {
cout << "Message 2: " << get<string>(message) << endl; cout << "Message 2: " << get<string>(message) << endl;
} }
}); });
dc->send("Hello from 2");
std::atomic_store(&dc2, dc); std::atomic_store(&dc2, dc);
}); });
auto dc1 = pc1.createDataChannel("test"); auto dc1 = pc1.createDataChannel("test");
dc1->onOpen([wdc1 = make_weak_ptr(dc1)]() {
auto dc1 = wdc1.lock();
if (!dc1)
return;
cout << "DataChannel 1: Open" << endl; dc1->onOpen([wdc1 = make_weak_ptr(dc1)]() {
dc1->send("Hello from 1"); if (auto dc1 = wdc1.lock()) {
cout << "DataChannel 1: Open" << endl;
dc1->send("Hello from 1");
}
}); });
dc1->onMessage([](const variant<binary, string> &message) { dc1->onMessage([](const variant<binary, string> &message) {
if (holds_alternative<string>(message)) { if (holds_alternative<string>(message)) {
cout << "Message 1: " << get<string>(message) << endl; cout << "Message 1: " << get<string>(message) << endl;
@ -144,7 +149,7 @@ void test_connectivity() {
if (!adc2 || !adc2->isOpen() || !dc1->isOpen()) if (!adc2 || !adc2->isOpen() || !dc1->isOpen())
throw runtime_error("DataChannel is not open"); throw runtime_error("DataChannel is not open");
if (dc1->maxMessageSize() != 1048576 || dc2->maxMessageSize() != 1048576) if (dc1->maxMessageSize() != CUSTOM_MAX_MESSAGE_SIZE || dc2->maxMessageSize() != CUSTOM_MAX_MESSAGE_SIZE)
throw runtime_error("DataChannel max message size is incorrect"); throw runtime_error("DataChannel max message size is incorrect");
if (auto addr = pc1.localAddress()) if (auto addr = pc1.localAddress())
@ -175,25 +180,26 @@ void test_connectivity() {
return; return;
} }
dc->onOpen([wdc = make_weak_ptr(dc)]() {
if (auto dc = wdc.lock())
dc->send("Second hello from 2");
});
dc->onMessage([](variant<binary, string> message) { dc->onMessage([](variant<binary, string> message) {
if (holds_alternative<string>(message)) { if (holds_alternative<string>(message)) {
cout << "Second Message 2: " << get<string>(message) << endl; cout << "Second Message 2: " << get<string>(message) << endl;
} }
}); });
dc->send("Send hello from 2");
std::atomic_store(&second2, dc); std::atomic_store(&second2, dc);
}); });
auto second1 = pc1.createDataChannel("second"); auto second1 = pc1.createDataChannel("second");
second1->onOpen([wsecond1 = make_weak_ptr(dc1)]() { second1->onOpen([wsecond1 = make_weak_ptr(dc1)]() {
auto second1 = wsecond1.lock(); if (auto second1 = wsecond1.lock()) {
if (!second1) cout << "Second DataChannel 1: Open" << endl;
return; second1->send("Second hello from 1");
}
cout << "Second DataChannel 1: Open" << endl;
second1->send("Second hello from 1");
}); });
dc1->onMessage([](const variant<binary, string> &message) { dc1->onMessage([](const variant<binary, string> &message) {
if (holds_alternative<string>(message)) { if (holds_alternative<string>(message)) {

View File

@ -108,14 +108,17 @@ void test_turn_connectivity() {
return; return;
} }
dc->onOpen([wdc = make_weak_ptr(dc)]() {
if (auto dc = wdc.lock())
dc->send("Hello from 2");
});
dc->onMessage([](variant<binary, string> message) { dc->onMessage([](variant<binary, string> message) {
if (holds_alternative<string>(message)) { if (holds_alternative<string>(message)) {
cout << "Message 2: " << get<string>(message) << endl; cout << "Message 2: " << get<string>(message) << endl;
} }
}); });
dc->send("Hello from 2");
std::atomic_store(&dc2, dc); std::atomic_store(&dc2, dc);
}); });
@ -175,14 +178,17 @@ void test_turn_connectivity() {
return; return;
} }
dc->onOpen([wdc = make_weak_ptr(dc)]() {
if (auto dc = wdc.lock())
dc->send("Second hello from 2");
});
dc->onMessage([](variant<binary, string> message) { dc->onMessage([](variant<binary, string> message) {
if (holds_alternative<string>(message)) { if (holds_alternative<string>(message)) {
cout << "Second Message 2: " << get<string>(message) << endl; cout << "Second Message 2: " << get<string>(message) << endl;
} }
}); });
dc->send("Send hello from 2");
std::atomic_store(&second2, dc); std::atomic_store(&second2, dc);
}); });