Compare commits

...

61 Commits

Author SHA1 Message Date
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 2471 additions and 1724 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.7)
project(libdatachannel
VERSION 0.12.1
VERSION 0.13.0
LANGUAGES CXX)
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/datachannel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/init.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/log.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.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/mediahandlerrootelement.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.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/rtcpreceivingsession.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/init.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/log.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/global.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.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/dtlstransport.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/logcounter.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/dtlstransport.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/queue.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.hpp
@ -213,17 +215,17 @@ set_target_properties(datachannel-static PROPERTIES
VERSION ${PROJECT_VERSION}
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}/src)
target_link_libraries(datachannel PUBLIC Threads::Threads plog::plog)
target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp)
target_link_libraries(datachannel PUBLIC Threads::Threads)
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 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
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 PRIVATE Usrsctp::Usrsctp)
target_link_libraries(datachannel-static PUBLIC Threads::Threads)
target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp plog::plog)
if(WIN32)
target_link_libraries(datachannel PUBLIC ws2_32) # winsock2
@ -310,9 +312,6 @@ endif()
add_library(LibDataChannel::LibDataChannel ALIAS datachannel)
add_library(LibDataChannel::LibDataChannelStatic ALIAS datachannel-static)
install(TARGETS datachannel LIBRARY DESTINATION lib)
install(FILES ${LIBDATACHANNEL_HEADERS} DESTINATION include/rtc)
if(NOT MSVC)
target_compile_options(datachannel PRIVATE -Wall -Wextra)
target_compile_options(datachannel-static PRIVATE -Wall -Wextra)
@ -328,6 +327,22 @@ if(WARNINGS_AS_ERRORS)
endif()
endif()
install(TARGETS datachannel EXPORT datachannel-export
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install(FILES ${LIBDATACHANNEL_HEADERS}
DESTINATION include/rtc
)
install(
EXPORT datachannel-export
NAMESPACE LibDatachannel::
DESTINATION share/cmake/libdatachannel
)
# Tests
if(NOT NO_TESTS)
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")

View File

@ -12,9 +12,12 @@ feature.compose <gnutls>on
lib libdatachannel
: # sources
[ glob ./src/*.cpp ]
[ glob ./src/impl/*.cpp ]
: # requirements
<cxxstd>17
<include>./include
<include>./include/rtc
<include>./src
<define>RTC_ENABLE_MEDIA=0
<define>RTC_ENABLE_WEBSOCKET=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
# brew install openssl
OPENSSL_INCLUDE = /usr/local/opt/openssl/include ;
OPENSSL_INCLUDE = /opt/homebrew/opt/openssl /usr/local/opt/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
# 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) = ""
{
@ -217,7 +220,7 @@ rule openssl-include-path ( properties * )
{
# on macOS, default to pick up openssl from the homebrew installation
# 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) = ""
{

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)
- [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).
Additionally, it contains two debugging tools for libdatachannel with copy-pasting as signaling:

View File

@ -1,8 +1,9 @@
# 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)
- Constant Throughput Set: Send desired amount of data per second
- Multiple Data Channel: Create desried count of data channel
## Start Signaling Server
- 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 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
@ -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);
```bash
Stun server is stun:stun.l.google.com:19302
The local ID is: EQmF
Url is ws://localhost:8000/EQmF
The local ID is: H1E3
Url is ws://localhost:8000/H1E3
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-03-25 14:21:58.045 INFO [21386] [rtc::impl::TcpTransport::runLoop@327] TCP connected
2021-03-25 14:21:58.046 INFO [21386] [rtc::impl::WsTransport::incoming@118] WebSocket open
2021-04-10 19:51:31.319 INFO [16449] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-04-10 19:51:31.319 INFO [16449] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-04-10 19:51:31.321 INFO [16449] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready
Enter a remote ID to send an offer:
0tDf
Offering to 0tDf
Creating DataChannel with label "benchmark"
2021-03-25 14:22:07.972 INFO [21379] [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-03-25 14:22:07.973 INFO [21379] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress
n790
Offering to n790
Creating DataChannel with label "DC-1"
2021-04-10 19:51:32.464 INFO [16442] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to 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-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
2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
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-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::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
2021-04-10 19:51:32.466 INFO [16450] [rtc::impl::PeerConnection::changeState@1016] Changed state to 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-03-25 14:22:08.055 INFO [21386] [rtc::impl::PeerConnection::changeSignalingState@992] 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-03-25 14:22:08.105 WARN [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101
2021-03-25 14:22:08.105 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful
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
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-04-10 19:51:32.489 INFO [16449] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-04-10 19:51:32.490 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-04-10 19:51:32.491 INFO [16453] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-04-10 19:51:32.497 INFO [16443] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
2021-04-10 19:51:32.497 INFO [16443] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
State: connected
DataChannel from 0tDf open
#2 Received: 41488 KB/s Sent: 42465 KB/s BufferSize: 65535
#3 Received: 43925 KB/s Sent: 43729 KB/s BufferSize: 65535
#4 Received: 42491 KB/s Sent: 42361 KB/s BufferSize: 65535
#5 Received: 45878 KB/s Sent: 45682 KB/s BufferSize: 65535
Stats# Received Total: 174 MB Sent Total: 175 MB RTT: 17 ms
DataChannel from n790 open
2021-04-10 19:51:32.542 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
2021-04-10 19:51:32.589 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
#1
DC-1 Received: 40789 KB/s Sent: 41180 KB/s BufferSize: 65535
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
#7 Received: 45749 KB/s Sent: 45488 KB/s BufferSize: 65535
#8 Received: 44055 KB/s Sent: 44055 KB/s BufferSize: 65535
#9 Received: 21572 KB/s Sent: 58199 KB/s BufferSize: 65535
#10 Received: 22940 KB/s Sent: 55005 KB/s BufferSize: 65535
Stats# Received Total: 353 MB Sent Total: 422 MB RTT: 15 ms
#6
DC-1 Received: 46235 KB/s Sent: 30433 KB/s BufferSize: 65535
TOTL Received: 46235 KB/s Sent: 30433 KB/s
#7
DC-1 Received: 47116 KB/s Sent: 28413 KB/s BufferSize: 65535
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
#12 Received: 29914 KB/s Sent: 48162 KB/s BufferSize: 65535
#13 Received: 31869 KB/s Sent: 45946 KB/s BufferSize: 65535
#14 Received: 22484 KB/s Sent: 53636 KB/s BufferSize: 65535
#15 Received: 16294 KB/s Sent: 56833 KB/s BufferSize: 65535
Stats# Received Total: 482 MB Sent Total: 682 MB RTT: 13 ms
#11
DC-1 Received: 42617 KB/s Sent: 39619 KB/s BufferSize: 65535
TOTL Received: 42617 KB/s Sent: 39619 KB/s
#12
DC-1 Received: 43792 KB/s Sent: 43338 KB/s BufferSize: 65535
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)
@ -92,64 +120,92 @@ Start second peer as;
Example Output (Offering Peer's Output);
```bash
Not Sending data. (One way benchmark).
Stun server is stun:stun.l.google.com:19302
The local ID is: XLLn
Url is ws://localhost:8000/XLLn
The local ID is: 7EaP
Url is ws://localhost:8000/7EaP
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-03-25 14:34:24.479 INFO [22332] [rtc::impl::TcpTransport::runLoop@327] TCP connected
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::WsTransport::incoming@118] WebSocket open
2021-04-10 19:54:36.857 INFO [16632] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-04-10 19:54:36.857 INFO [16632] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-04-10 19:54:36.858 INFO [16632] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready
Enter a remote ID to send an offer:
Okt4
Offering to Okt4
Creating DataChannel with label "benchmark"
2021-03-25 14:34:37.948 INFO [22325] [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-03-25 14:34:37.949 INFO [22325] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress
UDL4
Offering to UDL4
Creating DataChannel with label "DC-1"
2021-04-10 19:54:53.381 INFO [16625] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-04-10 19:54:53.382 INFO [16625] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-04-10 19:54:53.382 INFO [16625] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to 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-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
2021-04-10 19:54:53.383 INFO [16625] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
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-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::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
2021-04-10 19:54:53.384 INFO [16646] [rtc::impl::PeerConnection::changeState@1016] Changed state to 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-03-25 14:34:37.969 INFO [22332] [rtc::impl::PeerConnection::changeSignalingState@992] 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-03-25 14:34:37.971 INFO [22337] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-03-25 14:34:37.977 INFO [22327] [rtc::impl::SctpTransport::processNotification@708] SCTP connected
2021-03-25 14:34:37.977 INFO [22327] [rtc::impl::PeerConnection::changeState@964] Changed state to connected
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-04-10 19:54:53.475 INFO [16632] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-04-10 19:54:53.527 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
2021-04-10 19:54:53.575 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-04-10 19:54:53.625 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
#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
DataChannel from Okt4 open
2021-03-25 14:34:38.019 WARN [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101
2021-03-25 14:34:38.019 WARN [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101
2021-03-25 14:34:38.019 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete
DataChannel from UDL4 open
#2
DC-1 Received: 84326 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 84326 KB/s Sent: 0 KB/s
#3
DC-1 Received: 99387 KB/s Sent: 0 KB/s BufferSize: 0
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
2021-03-25 14:34:38.069 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
#1 Received: 0 KB/s Sent: 92223 KB/s BufferSize: 65535
#2 Received: 0 KB/s Sent: 89291 KB/s BufferSize: 65535
#3 Received: 0 KB/s Sent: 95087 KB/s BufferSize: 65535
#4 Received: 0 KB/s Sent: 101050 KB/s BufferSize: 65535
#5 Received: 0 KB/s Sent: 99778 KB/s BufferSize: 0
Stats# Received Total: 0 MB Sent Total: 480 MB RTT: 8 ms
#4
DC-1 Received: 94871 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 94871 KB/s Sent: 0 KB/s
#5
DC-1 Received: 96259 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 96259 KB/s Sent: 0 KB/s
Stats# Received Total: 377 MB Sent Total: 0 MB RTT: 2 ms
#6 Received: 0 KB/s Sent: 100366 KB/s BufferSize: 65535
#7 Received: 0 KB/s Sent: 101201 KB/s BufferSize: 65535
#8 Received: 0 KB/s Sent: 100892 KB/s BufferSize: 65535
#9 Received: 0 KB/s Sent: 101288 KB/s BufferSize: 65535
#10 Received: 0 KB/s Sent: 95676 KB/s BufferSize: 65535
Stats# Received Total: 0 MB Sent Total: 982 MB RTT: 8 ms
#6
DC-1 Received: 92873 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 92873 KB/s Sent: 0 KB/s
#7
DC-1 Received: 87724 KB/s Sent: 0 KB/s BufferSize: 0
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
#12 Received: 0 KB/s Sent: 105473 KB/s BufferSize: 65535
#13 Received: 0 KB/s Sent: 95549 KB/s BufferSize: 65535
#14 Received: 0 KB/s Sent: 100366 KB/s BufferSize: 65535
#15 Received: 0 KB/s Sent: 101336 KB/s BufferSize: 65535
Stats# Received Total: 0 MB Sent Total: 1484 MB RTT: 8 ms
#11
DC-1 Received: 103628 KB/s Sent: 0 KB/s BufferSize: 0
TOTL Received: 103628 KB/s Sent: 0 KB/s
#12
DC-1 Received: 106166 KB/s Sent: 0 KB/s BufferSize: 0
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
@ -159,61 +215,249 @@ Stats# Received Total: 0 MB Sent Total: 1484 MB RTT: 8 ms
Example Output (Offering Peer's Output);
```bash
Stun server is stun:stun.l.google.com:19302
The local ID is: 1w9O
Url is ws://localhost:8000/1w9O
The local ID is: 5zkC
Url is ws://localhost:8000/5zkC
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-03-25 14:29:38.697 INFO [21844] [rtc::impl::TcpTransport::runLoop@327] TCP connected
2021-03-25 14:29:38.698 INFO [21844] [rtc::impl::WsTransport::incoming@118] WebSocket open
2021-04-10 19:52:49.788 INFO [16530] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
2021-04-10 19:52:49.788 INFO [16530] [rtc::impl::TcpTransport::runLoop@331] TCP connected
2021-04-10 19:52:49.789 INFO [16530] [rtc::impl::WsTransport::incoming@118] WebSocket open
WebSocket connected, signaling ready
Enter a remote ID to send an offer:
zi4B
Offering to zi4B
Creating DataChannel with label "benchmark"
2021-03-25 14:29:48.729 INFO [21837] [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-03-25 14:29:48.729 INFO [21837] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress
WawD
Offering to WawD
Creating DataChannel with label "DC-1"
2021-04-10 19:52:57.720 INFO [16523] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
2021-04-10 19:52:57.721 INFO [16523] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
2021-04-10 19:52:57.721 INFO [16523] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to 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-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
2021-04-10 19:52:57.722 INFO [16523] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
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-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::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
2021-04-10 19:52:57.722 INFO [16533] [rtc::impl::PeerConnection::changeState@1016] Changed state to 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-03-25 14:29:48.732 INFO [21844] [rtc::impl::PeerConnection::changeSignalingState@992] 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-03-25 14:29:48.782 WARN [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101
2021-03-25 14:29:48.782 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete
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
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-04-10 19:52:57.727 INFO [16530] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
2021-04-10 19:52:57.826 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
2021-04-10 19:52:57.828 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
2021-04-10 19:52:57.829 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
2021-04-10 19:52:57.884 INFO [16535] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
2021-04-10 19:52:57.907 INFO [16526] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
2021-04-10 19:52:57.907 INFO [16526] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
State: connected
DataChannel from zi4B open
#1 Received: 0 KB/s Sent: 78 KB/s BufferSize: 0
#2 Received: 8002 KB/s Sent: 7999 KB/s BufferSize: 0
#3 Received: 8002 KB/s Sent: 7998 KB/s BufferSize: 0
#4 Received: 7995 KB/s Sent: 8000 KB/s BufferSize: 0
#5 Received: 8000 KB/s Sent: 8001 KB/s BufferSize: 0
Stats# Received Total: 33 MB Sent Total: 33 MB RTT: 0 ms
DataChannel from WawD open
#1
DC-1 Received: 6515 KB/s Sent: 6577 KB/s BufferSize: 0
TOTL Received: 6515 KB/s Sent: 6577 KB/s
#2
DC-1 Received: 7998 KB/s Sent: 7999 KB/s BufferSize: 0
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
#7 Received: 7997 KB/s Sent: 7998 KB/s BufferSize: 0
#8 Received: 8001 KB/s Sent: 7999 KB/s BufferSize: 0
#9 Received: 7998 KB/s Sent: 8001 KB/s BufferSize: 0
#10 Received: 8003 KB/s Sent: 7998 KB/s BufferSize: 0
Stats# Received Total: 74 MB Sent Total: 74 MB RTT: 0 ms
#6
DC-1 Received: 8004 KB/s Sent: 7998 KB/s BufferSize: 0
TOTL Received: 8004 KB/s Sent: 7998 KB/s
#7
DC-1 Received: 7997 KB/s Sent: 8000 KB/s BufferSize: 0
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
#12 Received: 7999 KB/s Sent: 8000 KB/s BufferSize: 0
#13 Received: 8001 KB/s Sent: 8002 KB/s BufferSize: 0
#14 Received: 7998 KB/s Sent: 7999 KB/s BufferSize: 0
#15 Received: 8000 KB/s Sent: 7998 KB/s BufferSize: 0
Stats# Received Total: 115 MB Sent Total: 115 MB RTT: 0 ms
#11
DC-1 Received: 7997 KB/s Sent: 8001 KB/s BufferSize: 0
TOTL Received: 7997 KB/s Sent: 8001 KB/s
#12
DC-1 Received: 7981 KB/s Sent: 7997 KB/s BufferSize: 0
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 <chrono>
#include <future>
#include <iomanip>
#include <iostream>
#include <memory>
#include <random>
@ -61,7 +62,8 @@ string randomId(size_t length);
// Benchmark
const size_t messageSize = 65535;
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;
// Benchmark - enableThroughputSet params
@ -69,7 +71,7 @@ bool enableThroughputSet;
int throughtputSetAsKB;
int bufferSize;
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 {
Cmdline params(argc, argv);
@ -188,63 +190,67 @@ int main(int argc, char **argv) try {
auto pc = createPeerConnection(config, ws, id);
// We are the offerer, so create a data channel to initiate the process
const string label = "benchmark";
cout << "Creating DataChannel with label \"" << label << "\"" << endl;
auto dc = pc->createDataChannel(label);
for (int i = 1; i <= params.dataChannelCount(); i++) {
const string label = "DC-" + std::to_string(i);
cout << "Creating DataChannel with label \"" << label << "\"" << endl;
auto dc = pc->createDataChannel(label);
receivedSizeMap.emplace(label, 0);
sentSizeMap.emplace(label, 0);
// Set Buffer Size
dc->setBufferedAmountLowThreshold(bufferSize);
// Set Buffer Size
dc->setBufferedAmountLowThreshold(bufferSize);
dc->onOpen([id, wdc = make_weak_ptr(dc)]() {
cout << "DataChannel from " << id << " open" << endl;
if (noSend)
return;
dc->onOpen([id, wdc = make_weak_ptr(dc), label]() {
cout << "DataChannel from " << id << " open" << endl;
if (noSend)
return;
if (enableThroughputSet)
return;
if (enableThroughputSet)
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 {
while (dcLocked->bufferedAmount() <= bufferSize) {
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(messageData);
sentSize += messageData.size();
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)]() {
if (noSend)
return;
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
if (enableThroughputSet)
return;
dc->onMessage([id, wdc = make_weak_ptr(dc), label](variant<binary, string> data) {
if (holds_alternative<binary>(data))
receivedSizeMap.at(label) += get<binary>(data).size();
});
auto dcLocked = wdc.lock();
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);
dataChannelMap.emplace(label, dc);
}
const int duration = params.durationInSec() > 0 ? params.durationInSec() : INT32_MAX;
cout << "Benchmark will run for " << duration << " seconds" << endl;
@ -271,25 +277,39 @@ int main(int argc, char **argv) try {
binary tempMessageData(byteToSendThisLoop);
fill(tempMessageData.begin(), tempMessageData.end(), std::byte(0xFF));
if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) {
dc->send(tempMessageData);
sentSize += tempMessageData.size();
for (const auto &[label, dc] : dataChannelMap) {
if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) {
dc->send(tempMessageData);
sentSizeMap.at(label) += tempMessageData.size();
}
}
}
if (printCounter >= STEP_COUNT_FOR_1_SEC) {
unsigned long _receivedSize = receivedSize.exchange(0);
unsigned long _sentSize = sentSize.exchange(0);
const double elapsedTimeInSecs =
std::chrono::duration<double>(steady_clock::now() - printTime).count();
printTime = steady_clock::now();
cout << "#" << i / STEP_COUNT_FOR_1_SEC
<< " Received: " << static_cast<int>(_receivedSize / (elapsedTimeInSecs * 1000))
<< " KB/s"
<< " Sent: " << static_cast<int>(_sentSize / (elapsedTimeInSecs * 1000))
<< " KB/s"
<< " BufferSize: " << dc->bufferedAmount() << endl;
unsigned long receiveSpeedTotal = 0;
unsigned long sendSpeedTotal = 0;
cout << "#" << i / STEP_COUNT_FOR_1_SEC << endl;
for (const auto &[label, dc] : dataChannelMap) {
unsigned long channelReceiveSpeed = static_cast<int>(
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++;
printCounter = 0;
}
@ -308,12 +328,16 @@ int main(int argc, char **argv) try {
dataChannelMap.clear();
peerConnectionMap.clear();
receivedSizeMap.clear();
sentSizeMap.clear();
return 0;
} catch (const std::exception &e) {
std::cout << "Error: " << e.what() << std::endl;
dataChannelMap.clear();
peerConnectionMap.clear();
receivedSizeMap.clear();
sentSizeMap.clear();
return -1;
}
@ -346,13 +370,16 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
});
pc->onDataChannel([id](shared_ptr<DataChannel> dc) {
cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
<< endl;
const string label = dc->label();
cout << "DataChannel from " << id << " received with label \"" << label << "\"" << endl;
cout << "###########################################" << endl;
cout << "### Check other peer's screen for stats ###" << endl;
cout << "###########################################" << endl;
receivedSizeMap.emplace(dc->label(), 0);
sentSizeMap.emplace(dc->label(), 0);
// Set Buffer Size
dc->setBufferedAmountLowThreshold(bufferSize);
@ -360,7 +387,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
try {
while (dc->bufferedAmount() <= bufferSize) {
dc->send(messageData);
sentSize += messageData.size();
sentSizeMap.at(label) += messageData.size();
}
} catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl;
@ -370,7 +397,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
if (!noSend && enableThroughputSet) {
// Create Send Data Thread
// 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();
// Byte count to send for every loop
int byteToSendOnEveryLoop = throughtputSetAsKB * stepDurationInMs;
@ -399,7 +426,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
if (dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(tempMessageData);
sentSize += tempMessageData.size();
sentSizeMap.at(label) += tempMessageData.size();
}
} catch (const std::exception &e) {
std::cout << "Send failed: " << e.what() << std::endl;
@ -409,7 +436,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
}).detach();
}
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc)]() {
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc), label]() {
if (noSend)
return;
@ -424,7 +451,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
try {
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
dcLocked->send(messageData);
sentSize += messageData.size();
sentSizeMap.at(label) += messageData.size();
}
} catch (const std::exception &e) {
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->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))
receivedSize += get<binary>(data).size();
receivedSizeMap.at(label) += get<binary>(data).size();
});
dataChannelMap.emplace(id, dc);
dataChannelMap.emplace(label, dc);
});
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'},
{"throughtputSetAsKB", required_argument, NULL, 'r'},
{"bufferSize", required_argument, NULL, 'b'},
{"dataChannelCount", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}};
@ -68,9 +69,10 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
_p = false;
_r = 300;
_b = 0;
_c = 1;
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) {
case 'n':
_n = true;
@ -147,6 +149,15 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
}
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':
_h = true;
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\
[ -r ] [ --throughtputSetAsKB ] (type=INTEGER, range>0...INT_MAX, default=300)\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\
Display this help and exit.\n";
}

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
"name": "libdatachannel-signaling-server",
"version": "0.1.0",
"description": "Signaling server example for libdatachannel",
"main": "server.js",
"main": "signaling-server.js",
"scripts": {
"start": "node signaling-server.js",
"test": "echo \"Error: no test specified\" && exit 1"
@ -18,6 +18,6 @@
},
"homepage": "https://github.com/paullouisageneau/libdatachannel#readme",
"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/>.
*/
const fs = require('fs');
const http = require('http');
const websocket = require('websocket');

View File

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

View File

@ -19,10 +19,10 @@
#include "helpers.hpp"
#include <ctime>
#if _WIN32
#ifdef _WIN32
// 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 {
int tz_minuteswest;
@ -55,6 +55,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
}
return 0;
}
#else
#include <sys/time.h>
#endif
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);
auto track = pc->addTrack(video);
// 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
auto packetizer = shared_ptr<H264RtpPacketizer>(new H264RtpPacketizer(H264RtpPacketizer::Separator::Length, rtpConfig));
auto packetizer = make_shared<H264RtpPacketizer>(H264RtpPacketizer::Separator::Length, rtpConfig);
// create H264 handler
shared_ptr<H264PacketizationHandler> h264Handler(new H264PacketizationHandler(packetizer));
auto h264Handler = make_shared<H264PacketizationHandler>(packetizer);
// add RTCP SR handler
auto srReporter = make_shared<RtcpSrReporter>(rtpConfig);
h264Handler->addToChain(srReporter);
@ -242,7 +242,7 @@ shared_ptr<ClientTrackData> addAudio(const shared_ptr<PeerConnection> pc, const
audio.addSSRC(ssrc, cname, msid, cname);
auto track = pc->addTrack(audio);
// 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
auto packetizer = make_shared<OpusRtpPacketizer>(rtpConfig);
// create opus handler
@ -265,7 +265,7 @@ shared_ptr<Client> createPeerConnection(const Configuration &config,
weak_ptr<WebSocket> wws,
string id) {
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) {
cout << "State: " << state << endl;

View File

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

View File

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

View File

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

View File

@ -42,7 +42,14 @@ class RTC_CPP_EXPORT Description {
public:
enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
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, 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
* modify it under the terms of the GNU Lesser General Public
@ -16,27 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTC_LOG_H
#define RTC_LOG_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
#ifndef RTC_GLOBAL_H
#define RTC_GLOBAL_H
#include "common.hpp"
#include <chrono>
namespace rtc {
enum class LogLevel { // Don't change, it must match plog severity
@ -49,8 +35,29 @@ enum class LogLevel { // Don't change, it must match plog severity
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);
#endif
RTC_EXPORT void Preload();
RTC_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_EXPORT void SetSctpSettings(SctpSettings s);
} // namespace rtc
#endif

View File

@ -1,23 +1,23 @@
/*
* libdatachannel client example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef H264_PACKETIZATION_HANDLER_H
#define H264_PACKETIZATION_HANDLER_H
#ifndef RTC_H264_PACKETIZATION_HANDLER_H
#define RTC_H264_PACKETIZATION_HANDLER_H
#if RTC_ENABLE_MEDIA
@ -28,7 +28,7 @@
namespace rtc {
/// Handler for H264 packetization
class RTC_CPP_EXPORT H264PacketizationHandler : public MediaChainableHandler {
class RTC_CPP_EXPORT H264PacketizationHandler final : public MediaChainableHandler {
public:
/// Construct handler for H264 packetization.
/// @param packetizer RTP packetizer for h264
@ -39,4 +39,4 @@ public:
#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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef H264_RTP_PACKETIZER_H
#define H264_RTP_PACKETIZER_H
#ifndef RTC_H264_RTP_PACKETIZER_H
#define RTC_H264_RTP_PACKETIZER_H
#if RTC_ENABLE_MEDIA
@ -28,13 +28,13 @@
namespace rtc {
/// 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);
const uint16_t maximumFragmentSize;
public:
/// Default clock rate for H264 in RTP
static const auto defaultClockRate = 90 * 1000;
inline static const uint32_t defaultClockRate = 90 * 1000;
/// Nalunit separator
enum class Separator {
@ -64,4 +64,4 @@ private:
#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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_MEDIA_CHAINABLE_HANDLER_H

View File

@ -1,18 +1,19 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_MEDIA_HANDLER_ELEMENT_H

View File

@ -1,22 +1,23 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H
#define RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H
#ifndef RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
#define RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
#if RTC_ENABLE_MEDIA
@ -42,4 +43,4 @@ public:
#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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef NAL_UNIT_H
#define NAL_UNIT_H
#ifndef RTC_NAL_UNIT_H
#define RTC_NAL_UNIT_H
#if RTC_ENABLE_MEDIA
#include "common.hpp"
#include <cassert>
namespace rtc {
#pragma pack(push, 1)
/// Nalu header
struct RTC_CPP_EXPORT NalUnitHeader {
uint8_t _first = 0;
bool forbiddenBit() { return _first >> 7; }
uint8_t nri() { return _first >> 5 & 0x03; }
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 setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); }
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
private:
uint8_t _first = 0;
};
/// Nalu fragment header
struct RTC_CPP_EXPORT NalUnitFragmentHeader {
uint8_t _first = 0;
bool isStart() { return _first >> 7; }
bool reservedBit6() { return (_first >> 6) & 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 setReservedBit6(bool isSet) { _first = (_first & 0xBF) | (isSet << 5); }
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
private:
uint8_t _first = 0;
};
#pragma pack(pop)
@ -152,4 +152,4 @@ public:
#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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_OPUS_PACKETIZATION_HANDLER_H
@ -27,7 +27,7 @@
namespace rtc {
/// Handler for opus packetization
class RTC_CPP_EXPORT OpusPacketizationHandler : public MediaChainableHandler {
class RTC_CPP_EXPORT OpusPacketizationHandler final : public MediaChainableHandler {
public:
/// Construct handler for opus packetization.

View File

@ -1,19 +1,19 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_OPUS_RTP_PACKETIZER_H
@ -27,10 +27,10 @@
namespace rtc {
/// RTP packetizer for opus
class RTC_CPP_EXPORT OpusRtpPacketizer : public RtpPacketizer, public MediaHandlerRootElement {
class RTC_CPP_EXPORT OpusRtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement {
public:
/// 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.
/// @note RTP configuration is used in packetization process which may change some configuration

View File

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

View File

@ -46,7 +46,8 @@ extern "C" {
#define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU
#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)
#endif
@ -94,61 +95,30 @@ typedef enum {
RTC_CERTIFICATE_RSA = 2,
} rtcCertificateType;
#if RTC_ENABLE_MEDIA
typedef enum {
// video
RTC_CODEC_H264 = 0,
RTC_CODEC_VP8 = 1,
RTC_CODEC_VP9 = 2,
// video
RTC_CODEC_H264 = 0,
RTC_CODEC_VP8 = 1,
RTC_CODEC_VP9 = 2,
// audio
RTC_CODEC_OPUS = 128
// audio
RTC_CODEC_OPUS = 128
} rtcCodec;
typedef enum {
RTC_DIRECTION_UNKNOWN = 0,
RTC_DIRECTION_SENDONLY = 1,
RTC_DIRECTION_RECVONLY = 2,
RTC_DIRECTION_SENDRECV = 3,
RTC_DIRECTION_INACTIVE = 4
RTC_DIRECTION_UNKNOWN = 0,
RTC_DIRECTION_SENDONLY = 1,
RTC_DIRECTION_RECVONLY = 2,
RTC_DIRECTION_SENDRECV = 3,
RTC_DIRECTION_INACTIVE = 4
} rtcDirection;
#endif // RTC_ENABLE_MEDIA
#define RTC_ERR_SUCCESS 0
#define RTC_ERR_INVALID -1 // invalid argument
#define RTC_ERR_FAILURE -2 // runtime error
#define RTC_ERR_NOT_AVAIL -3 // element not available
#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 *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
void *ptr);
@ -167,14 +137,28 @@ typedef void(RTC_API *rtcBufferedAmountLowCallbackFunc)(int id, void *ptr);
typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
// Log
// NULL cb on the first call will log to stdout
RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
// User pointer
RTC_EXPORT void rtcSetUserPointer(int id, void *ptr);
RTC_EXPORT void * rtcGetUserPointer(int i);
RTC_EXPORT void *rtcGetUserPointer(int i);
// 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 rtcDeletePeerConnection(int pc);
@ -201,6 +185,22 @@ RTC_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, c
int remoteSize);
// 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 rtcCreateDataChannel(int pc, const char *label); // returns dc id
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);
// 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 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 rtcGetTrackDescription(int tr, char *buffer, int size);
// Media
#if RTC_ENABLE_MEDIA
/// Add track
/// @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);
// Media
/// Set H264PacketizationHandler for track
/// @param tr Track id
/// @param ssrc SSRC
/// @param cname CName
/// @param payloadType Payload Type
/// @param clockRate Clock rate
/// @param maxFragmentSize Maximum NALU fragment size
/// @param sequenceNumber Sequence number
/// @param timestamp Timestamp
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);
typedef struct {
uint32_t ssrc;
const char *cname;
uint8_t payloadType;
uint32_t clockRate;
uint16_t maxFragmentSize; // Maximum NALU fragment size
uint16_t sequenceNumber;
uint32_t timestamp;
} rtcPacketizationHandlerInit;
/// Set OpusPacketizationHandler for track
/// @param tr Track id
/// @param ssrc SSRC
/// @param cname CName
/// @param payloadType Payload Type
/// @param clockRate Clock rate
/// @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);
typedef struct {
double seconds; // Start time in seconds
bool since1970; // true if seconds since 1970
// false if seconds since 1900
uint32_t timestamp; // Start timestamp
} rtcStartTime;
/// Chain RtcpSrReporter to handler chain for given track
/// @param tr Track id
int rtcChainRtcpSrReporter(int tr);
// Set H264PacketizationHandler for track
RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
/// Chain RtcpNackResponder to handler chain for given track
/// @param tr Track id
/// @param maxStoredPacketsCount Maximum stored packet count
int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount);
// Set OpusPacketizationHandler for track
RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
// 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
/// @param startTime_s Start time in seconds
/// @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);
RTC_EXPORT int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime);
/// Start stats recording for RTCP Sender Reporter
/// @param id Track identifier
int rtcStartRtcpSenderReporterRecording(int id);
// Start stats recording for RTCP Sender Reporter
RTC_EXPORT int rtcStartRtcpSenderReporterRecording(int id);
/// Transform seconds to timestamp using track's clock rate
/// @param id Track id
/// @param seconds Seconds
/// @param timestamp Pointer to result
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t * timestamp);
// Transform seconds to timestamp using track's clock rate
// Result is written to timestamp
RTC_EXPORT int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
/// Transform timestamp to seconds using track's clock rate
/// @param id Track id
/// @param timestamp Timestamp
/// @param seconds Pointer for result
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double * seconds);
// Transform timestamp to seconds using track's clock rate
// Result is written to seconds
RTC_EXPORT int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds);
/// Get current timestamp
/// @param id Track id
/// @param timestamp Pointer for result
int rtcGetCurrentTrackTimestamp(int id, uint32_t * timestamp);
// Get current timestamp
// Result is written to timestamp
RTC_EXPORT int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp);
/// Get start timestamp for track identified by given id
/// @param id Track id
/// @param timestamp Pointer for result
int rtcGetTrackStartTimestamp(int id, uint32_t * timestamp);
// Get start timestamp for track identified by given id
// Result is written to timestamp
RTC_EXPORT int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp);
/// Set RTP timestamp for track identified by given id
/// @param id Track id
/// @param timestamp New timestamp
int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp);
// Set RTP timestamp for track identified by given id
RTC_EXPORT int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp);
/// Get timestamp of previous RTCP SR
/// @param id Track id
/// @param timestamp Pointer for result
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t * timestamp);
// Get timestamp of previous RTCP SR
// Result is written to timestamp
RTC_EXPORT int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp);
/// Set `NeedsToReport` flag in RtcpSrReporter handler identified by given track id
/// @param id Track id
int rtcSetNeedsToSendRtcpSr(int id);
// Set NeedsToReport flag in RtcpSrReporter handler identified by given track id
RTC_EXPORT int rtcSetNeedsToSendRtcpSr(int id);
#endif // RTC_ENABLE_MEDIA
// WebSocket
#if RTC_ENABLE_WEBSOCKET
// WebSocket
typedef struct {
bool disableTlsVerification; // if true, don't verify the TLS certificate
} rtcWsConfiguration;
@ -322,9 +310,11 @@ typedef struct {
RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id
RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config);
RTC_EXPORT int rtcDeleteWebsocket(int ws);
#endif
// DataChannel, Track, and WebSocket common API
RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb);
RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc 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);
// DataChannel, Track, and WebSocket common extended API
RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive
RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb);
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 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
} // extern "C"
#endif

View File

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

View File

@ -1,18 +1,19 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_RTCP_NACK_RESPONDER_H
@ -27,11 +28,11 @@
namespace rtc {
class RTC_CPP_EXPORT RtcpNackResponder: public MediaHandlerElement {
class RTC_CPP_EXPORT RtcpNackResponder final: public MediaHandlerElement {
/// Packet storage
class RTC_CPP_EXPORT Storage {
/// Packet storage element
struct RTC_CPP_EXPORT Element {
Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next = nullptr);

View File

@ -1,18 +1,19 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_RTCP_SENDER_REPORTABLE_H
@ -26,7 +27,7 @@
namespace rtc {
class RTC_CPP_EXPORT RtcpSrReporter: public MediaHandlerElement {
class RTC_CPP_EXPORT RtcpSrReporter final: public MediaHandlerElement {
bool needsToReport = false;

View File

@ -21,23 +21,9 @@
#ifndef RTC_RTP_HPP
#define RTC_RTP_HPP
#include "log.hpp"
#include "common.hpp"
#include <cmath>
#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
#include <vector>
namespace rtc {
@ -45,63 +31,40 @@ typedef uint32_t SSRC;
#pragma pack(push, 1)
struct RTP {
private:
struct RTC_CPP_EXPORT RTP {
uint8_t _first;
uint8_t _payloadType;
uint16_t _seqNumber;
uint32_t _timestamp;
SSRC _ssrc;
SSRC _csrc[16];
public:
SSRC csrc[16];
[[nodiscard]] uint8_t version() const;
[[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; }
inline bool padding() const { return (_first >> 5) & 0x01; }
inline bool extension() const { return (_first >> 4) & 0x01; }
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); }
[[nodiscard]] size_t getSize() const;
[[nodiscard]] const char *getBody() const;
[[nodiscard]] char *getBody();
inline size_t getSize() const {
return reinterpret_cast<const char *>(&csrc) - reinterpret_cast<const char *>(this) +
sizeof(SSRC) * csrcCount();
}
void log() const;
[[nodiscard]] char *getBody() {
return reinterpret_cast<char *>(&csrc) + sizeof(SSRC) * csrcCount();
}
[[nodiscard]] const char *getBody() const {
return reinterpret_cast<const char *>(&csrc) + sizeof(SSRC) * csrcCount();
}
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();
}
void preparePacket();
void setSeqNumber(uint16_t newSeqNo);
void setPayloadType(uint8_t newPayloadType);
void setSsrc(uint32_t in_ssrc);
void setMarker(bool marker);
void setTimestamp(uint32_t i);
};
struct RTCP_ReportBlock {
SSRC ssrc;
private:
struct RTC_CPP_EXPORT RTCP_ReportBlock {
SSRC _ssrc;
uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit
uint16_t _seqNoCycles;
uint16_t _highestSeqNo;
@ -109,136 +72,68 @@ private:
uint32_t _lastReport;
uint32_t _delaySinceLastReport;
public:
inline void 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);
[[nodiscard]] uint16_t seqNoCycles() const;
[[nodiscard]] uint16_t highestSeqNo() const;
[[nodiscard]] uint32_t jitter() const;
[[nodiscard]] uint32_t delaySinceSR() const;
// Middle 32 bits of NTP Timestamp
// this->lastReport = lastSR_NTP >> 16u;
setNTPOfSR(uint64_t(lastSR_NTP));
setDelaySinceSR(uint32_t(lastSR_DELAY));
[[nodiscard]] SSRC getSSRC() const;
[[nodiscard]] uint32_t getNTPOfSR() const;
[[nodiscard]] unsigned int getLossPercentage() const;
[[nodiscard]] unsigned int getPacketLostCount() const;
// The delay, expressed in units of 1/65536 seconds
// this->delaySinceLastReport = lastSR_DELAY;
}
void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets,
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); }
[[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();
}
void log() const;
};
struct RTCP_HEADER {
private:
struct RTC_CPP_EXPORT RTCP_HEADER {
uint8_t _first;
uint8_t _payloadType;
uint16_t _length;
public:
inline uint8_t version() const { return _first >> 6; }
inline bool padding() const { return (_first >> 5) & 0x01; }
inline uint8_t reportCount() const { return _first & 0x0F; }
inline uint8_t payloadType() const { return _payloadType; }
inline uint16_t length() const { return ntohs(_length); }
inline size_t lengthInBytes() const { return (1 + length()) * 4; }
[[nodiscard]] uint8_t version() const;
[[nodiscard]] bool padding() const;
[[nodiscard]] uint8_t reportCount() const;
[[nodiscard]] uint8_t payloadType() const;
[[nodiscard]] uint16_t length() const;
[[nodiscard]] size_t lengthInBytes() const;
inline void setPayloadType(uint8_t type) { _payloadType = type; }
inline void setReportCount(uint8_t count) {
_first = (_first & 0b11100000u) | (count & 0b00011111u);
}
inline void setLength(uint16_t length) { _length = htons(length); }
void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length);
void setPayloadType(uint8_t type);
void setReportCount(uint8_t count);
void setLength(uint16_t length);
inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) {
_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();
}
void log() const;
};
struct RTCP_FB_HEADER {
struct RTC_CPP_EXPORT RTCP_FB_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() {
header.log();
PLOG_VERBOSE << "FB: "
<< " packet sender: " << getPacketSenderSSRC()
<< " media source: " << getMediaSourceSSRC();
}
void log() const;
};
struct RTCP_SR {
struct RTC_CPP_EXPORT RTCP_SR {
RTCP_HEADER header;
SSRC _senderSSRC;
private:
uint64_t _ntpTimestamp;
uint32_t _rtpTimestamp;
uint32_t _packetCount;
@ -246,418 +141,175 @@ private:
RTCP_ReportBlock _reportBlocks;
public:
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]] static unsigned int Size(unsigned int reportCount);
[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
return &_reportBlocks + num;
}
[[nodiscard]] uint64_t ntpTimestamp() const;
[[nodiscard]] uint32_t rtpTimestamp() const;
[[nodiscard]] uint32_t packetCount() const;
[[nodiscard]] uint32_t octetCount() const;
[[nodiscard]] uint32_t senderSSRC() const;
[[nodiscard]] static unsigned int size(unsigned int reportCount) {
return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock);
}
[[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
[[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
[[nodiscard]] unsigned int size(unsigned int reportCount);
[[nodiscard]] size_t getSize() const;
[[nodiscard]] inline size_t 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 preparePacket(SSRC senderSSRC, uint8_t reportCount);
void setNtpTimestamp(uint64_t ts);
void setRtpTimestamp(uint32_t ts);
void setOctetCount(uint32_t ts);
void setPacketCount(uint32_t ts);
inline uint64_t ntpTimestamp() const { return ntohll(_ntpTimestamp); }
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();
}
}
void log() const;
};
struct RTCP_SDES_ITEM {
public:
struct RTC_CPP_EXPORT RTCP_SDES_ITEM {
uint8_t type;
private:
uint8_t _length;
char _text[1];
public:
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");
[[nodiscard]] static unsigned int Size(uint8_t textLength);
_length = uint8_t(text.size());
memcpy(_text, text.data(), text.size());
}
[[nodiscard]] string text() const;
[[nodiscard]] uint8_t length() const;
inline uint8_t length() { return _length; }
[[nodiscard]] static unsigned int size(uint8_t textLength) { return textLength + 2; }
void setText(string text);
};
struct RTCP_SDES_CHUNK {
private:
SSRC _ssrc;
RTCP_SDES_ITEM _items;
public:
inline SSRC ssrc() const { return ntohl(_ssrc); }
inline void setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); }
[[nodiscard]] static unsigned int Size(const std::vector<uint8_t> textLengths);
/// Get item at given index
/// @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);
}
[[nodiscard]] SSRC ssrc() const;
long safelyCountChunkSize(size_t maxChunkSize) {
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;
}
}
void setSSRC(SSRC ssrc);
[[nodiscard]] static unsigned int 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;
}
// Get item at given index
// All items with index < num must be valid, otherwise this function has undefined behaviour
// (use safelyCountChunkSize() to check if chunk is valid).
[[nodiscard]] const RTCP_SDES_ITEM *getItem(int num) const;
[[nodiscard]] RTCP_SDES_ITEM *getItem(int num);
/// Get size of chunk
/// @note All items must be valid, otherwise this function has undefined behaviour (use
/// `safelyCountChunkSize` to check if chunk is valid)
[[nodiscard]] unsigned int getSize() {
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);
}
// Get size of chunk
// All items must be valid, otherwise this function has undefined behaviour (use
// safelyCountChunkSize() to check if chunk is valid)
[[nodiscard]] unsigned int getSize() const;
long safelyCountChunkSize(size_t maxChunkSize) const;
};
struct RTCP_SDES {
struct RTC_CPP_EXPORT RTCP_SDES {
RTCP_HEADER header;
private:
RTCP_SDES_CHUNK _chunks;
public:
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);
}
[[nodiscard]] static unsigned int Size(const std::vector<std::vector<uint8_t>> lengths);
bool isValid() {
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;
}
}
bool isValid() const;
/// Returns number of chunks in this packet
/// @note Returns 0 if packet is invalid
inline unsigned int chunksCount() {
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;
}
// Returns number of chunks in this packet
// Returns 0 if packet is invalid
unsigned int chunksCount() const;
/// Get chunk at given index
/// @note All chunks (and their items) with index < `num` must be valid, otherwise this function
/// has undefined behaviour (use `isValid` to check if chunk is valid)
/// @param num Index of chunk to return
inline 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);
}
// Get chunk at given index
// All chunks (and their items) with index < `num` must be valid, otherwise this function has
// undefined behaviour (use `isValid` to check if chunk is valid).
const RTCP_SDES_CHUNK *getChunk(int num) const;
RTCP_SDES_CHUNK *getChunk(int num);
[[nodiscard]] static unsigned int 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;
}
void preparePacket(uint8_t chunkCount);
};
struct RTCP_RR {
struct RTC_CPP_EXPORT RTCP_RR {
RTCP_HEADER header;
SSRC _senderSSRC;
private:
SSRC _senderSSRC;
RTCP_ReportBlock _reportBlocks;
public:
[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
return &_reportBlocks + num;
}
[[nodiscard]] static size_t SizeWithReportBlocks(uint8_t reportCount);
inline SSRC senderSSRC() const { return ntohl(_senderSSRC); }
inline void setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); }
SSRC senderSSRC() const;
bool isSenderReport();
bool isReceiverReport();
[[nodiscard]] inline size_t 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()));
}
[[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
[[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
[[nodiscard]] size_t getSize() const;
inline void 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 preparePacket(SSRC senderSSRC, uint8_t reportCount);
void setSenderSSRC(SSRC ssrc);
inline static size_t sizeWithReportBlocks(uint8_t reportCount) {
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();
}
}
void log() const;
};
struct RTCP_REMB {
struct RTC_CPP_EXPORT RTCP_REMB {
RTCP_FB_HEADER header;
/*! \brief Unique identifier ('R' 'E' 'M' 'B') */
char id[4];
char _id[4]; // Unique identifier ('R' 'E' 'M' 'B')
uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask)
SSRC _ssrc[1];
/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */
uint32_t bitrate;
[[nodiscard]] static size_t SizeWithSSRCs(int count);
SSRC ssrc[1];
[[nodiscard]] unsigned int getSize() const;
[[nodiscard]] unsigned int 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 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);
}
void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate);
void setBitrate(unsigned int numSSRC, unsigned int in_bitrate);
void setSsrc(int iterator, SSRC newSssrc);
};
struct RTCP_PLI {
struct RTC_CPP_EXPORT RTCP_PLI {
RTCP_FB_HEADER header;
void preparePacket(SSRC messageSSRC) {
header.header.prepareHeader(206, 1, 2);
header.setPacketSenderSSRC(messageSSRC);
header.setMediaSourceSSRC(messageSSRC);
}
[[nodiscard]] static unsigned int Size();
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;
uint8_t seqNo;
uint8_t dummy1;
uint16_t dummy2;
};
struct RTCP_FIR {
struct RTC_CPP_EXPORT RTCP_FIR {
RTCP_FB_HEADER header;
RTCP_FIR_PART parts[1];
void 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;
}
static unsigned int Size();
void print() { header.log(); }
void preparePacket(SSRC messageSSRC, uint8_t seqNo);
[[nodiscard]] static unsigned int size() {
return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART);
}
void log() const;
};
struct RTCP_NACK_PART {
struct RTC_CPP_EXPORT RTCP_NACK_PART {
uint16_t _pid;
uint16_t _blp;
uint16_t getPID() { return ntohs(_pid); }
uint16_t getBLP() { return ntohs(_blp); }
uint16_t pid();
uint16_t blp();
void setPID(uint16_t pid) { _pid = htons(pid); }
void setBLP(uint16_t blp) { _blp = htons(blp); }
void setPid(uint16_t pid);
void setBlp(uint16_t blp);
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;
}
std::vector<uint16_t> getSequenceNumbers();
};
class RTCP_NACK {
public:
struct RTC_CPP_EXPORT RTCP_NACK {
RTCP_FB_HEADER header;
RTCP_NACK_PART parts[1];
public:
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount));
header.setMediaSourceSSRC(ssrc);
header.setPacketSenderSSRC(ssrc);
}
[[nodiscard]] static unsigned int Size(unsigned int discreteSeqNoCount);
[[nodiscard]] unsigned int getSeqNoCount();
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount);
/**
* 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.
* @return true if the packet has grown, false otherwise.
*/
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; }
bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket);
};
class RTP_RTX {
private:
struct RTC_CPP_EXPORT RTP_RTX {
RTP header;
public:
size_t 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;
}
[[nodiscard]] const char *getBody() const;
[[nodiscard]] char *getBody();
[[nodiscard]] size_t getBodySize(size_t totalSize) const;
[[nodiscard]] size_t getSize() const;
[[nodiscard]] uint16_t getOriginalSeqNo() const;
[[nodiscard]] uint16_t getOriginalSeqNo() const {
return ntohs(*(uint16_t *)(header.getBody()));
}
// Returns the new size of the packet
size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType);
[[nodiscard]] char *getBody() { return header.getBody() + sizeof(uint16_t); }
[[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;
}
size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType);
};
#pragma pack(pop)

View File

@ -1,19 +1,19 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_RTP_PACKETIZATION_CONFIG_H

View File

@ -1,19 +1,19 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#ifndef RTC_RTP_PACKETIZER_H

View File

@ -22,6 +22,9 @@
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <tuple>
#include <utility>
namespace rtc {
@ -32,11 +35,10 @@ template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
// weak_ptr bind helper
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) {
using result_type = typename decltype(bound)::result_type;
if (auto shared_this = weak_this.lock())
return bound(args...);
else
return static_cast<result_type>(false);
return static_cast<decltype(bound(args...))>(false);
};
}
@ -58,40 +60,35 @@ private:
};
// callback with built-in synchronization
template <typename... Args> class synchronized_callback final {
template <typename... Args> class synchronized_callback {
public:
synchronized_callback() = default;
synchronized_callback(synchronized_callback &&cb) { *this = std::move(cb); }
synchronized_callback(const synchronized_callback &cb) { *this = cb; }
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) {
std::scoped_lock lock(mutex, cb.mutex);
callback = std::move(cb.callback);
cb.callback = nullptr;
set(std::exchange(cb.callback, nullptr));
return *this;
}
synchronized_callback &operator=(const synchronized_callback &cb) {
std::scoped_lock lock(mutex, cb.mutex);
callback = cb.callback;
set(cb.callback);
return *this;
}
synchronized_callback &operator=(std::function<void(Args...)> func) {
std::lock_guard lock(mutex);
callback = std::move(func);
set(std::move(func));
return *this;
}
bool operator()(Args... args) const {
std::lock_guard lock(mutex);
if (!callback)
return false;
callback(std::move(args)...);
return true;
return call(std::move(args)...);
}
operator bool() const {
@ -103,11 +100,48 @@ public:
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;
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
template <typename T> using impl_ptr = std::shared_ptr<T>;
template <typename T> class CheshireCat {

View File

@ -17,7 +17,8 @@
*/
#include "candidate.hpp"
#include "globals.hpp"
#include "impl/internals.hpp"
#include <algorithm>
#include <array>

View File

@ -17,10 +17,9 @@
*/
#include "rtc.h"
#include "rtc.hpp"
#include "plog/Formatters/FuncMessageFormatter.h"
#include "impl/internals.hpp"
#include <chrono>
#include <exception>
@ -29,11 +28,6 @@
#include <unordered_map>
#include <utility>
#ifdef _WIN32
#include <codecvt>
#include <locale>
#endif
using namespace rtc;
using std::chrono::milliseconds;
@ -116,14 +110,14 @@ int emplaceTrack(shared_ptr<Track> ptr) {
void erasePeerConnection(int pc) {
std::lock_guard lock(mutex);
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);
}
void eraseDataChannel(int dc) {
std::lock_guard lock(mutex);
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);
}
@ -146,7 +140,7 @@ shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
return it->second;
} 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()) {
return it->second;
} 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));
}
shared_ptr<RtpPacketizationConfig> getRTPConfig(int id) {
shared_ptr<RtpPacketizationConfig> getRtpConfig(int id) {
std::lock_guard lock(mutex);
if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
return it->second;
} 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);
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>
getNewRtpPacketizationConfig(uint32_t ssrc, const char *cname, uint8_t payloadType,
uint32_t clockRate, uint16_t sequenceNumber, uint32_t timestamp) {
if (!cname) {
throw std::invalid_argument("Unexpected null pointer for cname");
}
createRtpPacketizationConfig(const rtcPacketizationHandlerInit *init) {
if (!init)
throw std::invalid_argument("Unexpected null pointer for packetization handler init");
return std::make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, clockRate,
sequenceNumber, timestamp);
if (!init->cname)
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
@ -287,58 +268,16 @@ int copyAndReturn(binary b, char *buffer, int 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
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
static optional<plogAppender> appender;
const auto severity = static_cast<plog::Severity>(level);
std::lock_guard lock(mutex);
if (appender) {
appender->setCallback(cb);
InitLogger(severity, nullptr); // change the severity
} else if (cb) {
appender.emplace(plogAppender(cb));
InitLogger(severity, &appender.value());
} else {
InitLogger(severity, nullptr); // log to stdout
}
LogCallback callback = nullptr;
if (cb)
callback = [cb](LogLevel level, string message) {
cb(static_cast<rtcLogLevel>(level), message.c_str());
};
InitLogger(static_cast<LogLevel>(level), callback);
}
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,
const char *_trackID) {
auto peerConnection = getPeerConnection(pc);
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;
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);
return tr;
});
}
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) {
int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
return wrap([&] {
auto peerConnection = getPeerConnection(pc);
auto direction = rtcDirectionToDirection(_direction);
if (!init)
throw std::invalid_argument("Unexpected null pointer for track init");
string mid = "video";
switch (codec) {
case RTC_CODEC_H264:
case RTC_CODEC_VP8:
case RTC_CODEC_VP9:
mid = "video";
break;
case RTC_CODEC_OPUS:
mid = "audio";
break;
}
auto direction = static_cast<Description::Direction>(init->direction);
if (_mid) {
mid = string(_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;
switch (codec) {
switch (init->codec) {
case RTC_CODEC_H264:
case RTC_CODEC_VP8:
case RTC_CODEC_VP9: {
auto desc = Description::Video(mid, direction);
switch (codec) {
switch (init->codec) {
case RTC_CODEC_H264:
desc.addH264Codec(payloadType);
desc.addH264Codec(init->payloadType);
break;
case RTC_CODEC_VP8:
desc.addVP8Codec(payloadType);
desc.addVP8Codec(init->payloadType);
break;
case RTC_CODEC_VP9:
desc.addVP8Codec(payloadType);
desc.addVP8Codec(init->payloadType);
break;
default:
break;
@ -510,9 +445,9 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
}
case RTC_CODEC_OPUS: {
auto desc = Description::Audio(mid, direction);
switch (codec) {
switch (init->codec) {
case RTC_CODEC_OPUS:
desc.addOpusCodec(payloadType);
desc.addOpusCodec(init->payloadType);
break;
default:
break;
@ -524,168 +459,16 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
break;
}
if (!optDescription.has_value()) {
if (!optDescription)
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)));
if (auto ptr = getUserPointer(pc)) {
rtcSetUserPointer(tr, *ptr);
}
return tr;
}
});
}
auto desc = std::move(*optDescription);
desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
init->msid ? std::make_optional(string(init->msid)) : nullopt,
init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
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) {
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 tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
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))
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
int rtcCreateWebSocket(const char *url) {
return wrap([&] {
auto ws = std::make_shared<WebSocket>();
@ -748,6 +665,7 @@ int rtcDeleteWebsocket(int ws) {
return RTC_ERR_SUCCESS;
});
}
#endif
int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
@ -1189,4 +1107,37 @@ int rtcReceiveMessage(int id, char *buffer, int *size) {
}
void rtcPreload() { rtc::Preload(); }
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 "globals.hpp"
#include "impl/internals.hpp"
#include "impl/channel.hpp"
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) {
impl()->messageCallback = callback;
// Pass pending messages
while (auto message = receive())
impl()->messageCallback(*message);
impl()->flushPendingMessages();
}
void Channel::onMessage(std::function<void(binary data)> binaryCallback,

View File

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

View File

@ -19,6 +19,8 @@
#include "description.hpp"
#include "impl/internals.hpp"
#include <algorithm>
#include <array>
#include <cctype>

95
src/global.cpp Normal file
View File

@ -0,0 +1,95 @@
/**
* 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

View File

@ -1,19 +1,19 @@
/*
* libdatachannel client example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA

View File

@ -1,25 +1,35 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "h264rtppacketizer.hpp"
#include "impl/internals.hpp"
#include <cassert>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
namespace rtc {
typedef enum {

View File

@ -20,22 +20,21 @@
namespace rtc::impl {
void Channel::triggerOpen() { openCallback(); }
void Channel::triggerOpen() {
mOpenTriggered = true;
openCallback();
flushPendingMessages();
}
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) {
if (count == 1)
availableCallback();
while (messageCallback && count--) {
auto message = receive();
if (!message)
break;
messageCallback(*message);
}
flushPendingMessages();
}
void Channel::triggerBufferedAmount(size_t amount) {
@ -45,13 +44,32 @@ void Channel::triggerBufferedAmount(size_t amount) {
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() {
mOpenTriggered = false;
openCallback = nullptr;
closedCallback = nullptr;
errorCallback = nullptr;
messageCallback = nullptr;
availableCallback = nullptr;
bufferedAmountLowCallback = nullptr;
messageCallback = nullptr;
}
} // namespace rtc::impl

View File

@ -38,17 +38,23 @@ struct Channel {
virtual void triggerAvailable(size_t count);
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<> availableCallback;
synchronized_callback<> bufferedAmountLowCallback;
std::atomic<size_t> bufferedAmount = 0;
std::atomic<size_t> bufferedAmountLowThreshold = 0;
private:
std::atomic<bool> mOpenTriggered = false;
};
} // namespace rtc::impl

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,17 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTC_GLOBALS_H
#define RTC_GLOBALS_H
#ifndef RTC_IMPL_INTERNALS_H
#define RTC_IMPL_INTERNALS_H
#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 {
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 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_MAX_MESSAGE_SIZE = 65536; // Remote max message size if not specified in SDP

View File

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

View File

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

View File

@ -18,12 +18,13 @@
#include "sctptransport.hpp"
#include "dtlstransport.hpp"
#include "globals.hpp"
#include "internals.hpp"
#include "logcounter.hpp"
#include <chrono>
#include <exception>
#include <iostream>
#include <limits>
#include <thread>
#include <vector>
@ -54,6 +55,26 @@
using namespace std::chrono_literals;
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 {
static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
@ -69,7 +90,8 @@ std::shared_mutex SctpTransport::InstancesMutex;
void SctpTransport::Init() {
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_path_rtx_max_default(5);
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path
@ -78,21 +100,31 @@ void SctpTransport::Init() {
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_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
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)
usrsctp_sysctl_set_sctp_pr_enable(1);
// 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
// Reduce SACK delay to 20ms by default
usrsctp_sysctl_set_sctp_delayed_sack_time_default(
to_uint32(s.delayedSackTime.value_or(20ms).count()));
}
void SctpTransport::Cleanup() {
@ -195,7 +227,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
// The MTU value provided specifies the space available for chunks in the
// 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
spp.spp_pathmtu = uint32_t(pmtu);
spp.spp_pathmtu = to_uint32(pmtu);
PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu;
}
@ -222,18 +254,28 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
std::to_string(errno));
// The default send and receive window size of usrsctp is 256KiB, which is too small for
// realistic RTTs, therefore we increase it to at least 1MiB for better performance.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
const size_t minBufferSize = 1024 * 1024;
int rcvBuf = 0;
socklen_t rcvBufLen = sizeof(rcvBuf);
if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen))
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
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
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)))
const int minBuf = int(std::min(maxMessageSize, size_t(std::numeric_limits<int>::max())));
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=" +
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=" +
std::to_string(errno));
}
@ -336,7 +378,7 @@ bool SctpTransport::send(message_ptr message) {
return true;
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;
}
@ -353,7 +395,7 @@ bool SctpTransport::flush() {
}
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) {
@ -458,7 +500,7 @@ bool SctpTransport::trySendQueue() {
if (!trySendMessage(message))
return false;
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;
}
@ -511,12 +553,12 @@ bool SctpTransport::trySendMessage(message_ptr message) {
case Reliability::Type::Rexmit:
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
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;
case Reliability::Type::Timed:
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
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;
default:
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
@ -548,10 +590,10 @@ bool SctpTransport::trySendMessage(message_ptr message) {
return true;
}
void SctpTransport::updateBufferedAmount(uint16_t streamId, long delta) {
void SctpTransport::updateBufferedAmount(uint16_t streamId, ptrdiff_t delta) {
// Requires mSendMutex to be locked
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)
mBufferedAmount.erase(it);
else

View File

@ -39,6 +39,7 @@ namespace rtc::impl {
class SctpTransport final : public Transport {
public:
static void Init();
static void SetSettings(const SctpSettings &s);
static void Cleanup();
using amount_callback = std::function<void(uint16_t streamId, size_t amount)>;
@ -83,7 +84,7 @@ private:
void doFlush();
bool trySendQueue();
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 sendReset(uint16_t streamId);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@
#if RTC_ENABLE_WEBSOCKET
#include "websocket.hpp"
#include "globals.hpp"
#include "internals.hpp"
#include "common.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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "mediachainablehandler.hpp"
#include "impl/internals.hpp"
#include <cassert>
namespace rtc {
MediaChainableHandler::MediaChainableHandler(shared_ptr<MediaHandlerRootElement> root): MediaHandler(), root(root), leaf(root) { }

View File

@ -1,24 +1,29 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "mediahandlerelement.hpp"
#include "impl/internals.hpp"
#include <cassert>
namespace rtc {
ChainedMessagesProduct make_chained_messages_product() {

View File

@ -1,18 +1,19 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA

View File

@ -1,25 +1,26 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "nalunit.hpp"
#include "globals.hpp"
#include "impl/internals.hpp"
#include <cmath>

View File

@ -1,19 +1,19 @@
/*
* libdatachannel client example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA

View File

@ -1,25 +1,27 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "opusrtppacketizer.hpp"
#include <cassert>
namespace rtc {
OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)

View File

@ -24,6 +24,7 @@
#include "impl/certificate.hpp"
#include "impl/dtlstransport.hpp"
#include "impl/icetransport.hpp"
#include "impl/internals.hpp"
#include "impl/peerconnection.hpp"
#include "impl/processor.hpp"
#include "impl/sctptransport.hpp"
@ -266,7 +267,7 @@ shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, DataChan
void PeerConnection::onDataChannel(
std::function<void(shared_ptr<DataChannel> dataChannel)> callback) {
impl()->dataChannelCallback = callback;
impl()->triggerDataChannel(); // trigger pending DataChannels
impl()->flushPendingDataChannels();
}
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) {
impl()->trackCallback = callback;
impl()->triggerTrack(); // trigger pending tracks
impl()->flushPendingTracks();
}
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
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "rtcpnackresponder.hpp"
#include "impl/internals.hpp"
#include <cassert>
namespace rtc {
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) {
continue;
}
auto fieldsCount = nack->getSeqNoCount();
std::vector<uint16_t> missingSequenceNumbers{};

View File

@ -97,7 +97,7 @@ void RtcpReceivingSession::requestBitrate(unsigned int newBitrate) {
}
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());
remb->preparePacket(mSsrc, 1, bitrate);
remb->setSsrc(0, mSsrc);
@ -106,7 +106,7 @@ void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
}
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());
rr->preparePacket(mSsrc, 1);
rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS,
@ -132,7 +132,7 @@ bool RtcpReceivingSession::requestKeyframe() {
}
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());
pli->preparePacket(mSsrc);
send(msg);

View File

@ -1,24 +1,28 @@
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "rtcpsrreporter.hpp"
#include <cmath>
#include <cassert>
namespace rtc {
ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) {
@ -60,8 +64,8 @@ uint64_t RtcpSrReporter::secondsToNTP(double seconds) {
void RtcpSrReporter::setNeedsToReport() { needsToReport = true; }
message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) {
auto srSize = RTCP_SR::size(0);
auto msg = make_message(srSize + RTCP_SDES::size({{uint8_t(rtpConfig->cname.size())}}),
auto srSize = RTCP_SR::Size(0);
auto msg = make_message(srSize + RTCP_SDES::Size({{uint8_t(rtpConfig->cname.size())}}),
Message::Type::Control);
auto sr = reinterpret_cast<RTCP_SR *>(msg->data());
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)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "rtppacketizationconfig.hpp"
#include <cassert>
namespace rtc {
RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType,

View File

@ -1,25 +1,27 @@
/*
* libdatachannel streamer example
/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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 General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
* 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
*/
#if RTC_ENABLE_MEDIA
#include "rtppacketizer.hpp"
#include <cstring>
namespace rtc {
RtpPacketizer::RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
@ -37,7 +39,7 @@ binary_ptr RtpPacketizer::packetize(shared_ptr<binary> payload, bool setMark) {
rtp->setMarker(true);
}
rtp->preparePacket();
memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size());
std::memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size());
return msg;
}

View File

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

View File

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

View File

@ -121,12 +121,11 @@ size_t benchmark(milliseconds duration) {
}
} catch (const std::exception &e) {
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]() {
auto dc1 = wdc1.lock();
if (!dc1)

View File

@ -137,11 +137,11 @@ static void RTC_API dataChannelCallback(int pc, int dc, void *ptr) {
return;
}
rtcSetOpenCallback(dc, openCallback);
rtcSetClosedCallback(dc, closedCallback);
rtcSetMessageCallback(dc, messageCallback);
peer->dc = dc;
peer->connected = true;
const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
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) {
Peer *peer = (Peer *)ptr;
peer->tr = tr;
peer->connected = true;
rtcSetOpenCallback(tr, openCallback);
rtcSetClosedCallback(tr, closedCallback);
char buffer[1024];

View File

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

View File

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