mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-23 15:48:03 +00:00
Compare commits
104 Commits
Author | SHA1 | Date | |
---|---|---|---|
4cdb788124 | |||
6255ff1995 | |||
1d47294050 | |||
86f93e9aa3 | |||
d218e7923c | |||
2d97cc18c6 | |||
76d2d3d97f | |||
1156fbe434 | |||
983b5759f3 | |||
79242e27ed | |||
39e51a8345 | |||
f4aae34874 | |||
34469d16ae | |||
e6a9650523 | |||
a9057a02e5 | |||
a2b019465c | |||
8bdce69ab7 | |||
78ca3a318f | |||
e88197646d | |||
c5e4b972c2 | |||
4cdde18e4b | |||
41cba8a35a | |||
6c683b326d | |||
a152edf256 | |||
8f50eeb0f2 | |||
1105a4faec | |||
8184d1d60e | |||
38e1a946b0 | |||
8522446d6c | |||
8da8c8a6d0 | |||
6a4a22a87c | |||
724fefbfdb | |||
83cc26d4a5 | |||
1cfefd9dcd | |||
fbe141301c | |||
811a6b8a26 | |||
ddbd963e7e | |||
05a37c8306 | |||
a9ca8b687b | |||
e91880141a | |||
fd97f98f23 | |||
5c8d63ad78 | |||
c5cb81762c | |||
0b50fc4bb0 | |||
76d9ce5ba3 | |||
f795e3293f | |||
34aad791c6 | |||
30703741e5 | |||
124c073821 | |||
9457492169 | |||
384c84e8aa | |||
e4ab5273fc | |||
b315869989 | |||
aea6708d27 | |||
2166386d42 | |||
f88394ab75 | |||
ba7e0e2a35 | |||
fba965b46c | |||
eff0faf6e1 | |||
cd68d1dba7 | |||
ce9fa374d0 | |||
2bf03205cf | |||
07a5591cda | |||
282ca48b12 | |||
bf0b3ce1b9 | |||
48a275f830 | |||
a15b2ad468 | |||
afd4639d2d | |||
653ec35ba8 | |||
2d344f1186 | |||
13f3624aee | |||
ebe64ed8ef | |||
ae429410fe | |||
bbbc8ca4e6 | |||
5346d31cc1 | |||
d86de619dc | |||
d62166e1a7 | |||
b353fbe44d | |||
079926443c | |||
2ed6845201 | |||
6aee0ff12c | |||
6cea78c618 | |||
c929be592b | |||
0c882d074e | |||
4ca78db146 | |||
2fd3da482a | |||
9bc9eea5b4 | |||
d7261dd0ac | |||
436d77eab7 | |||
93b598a78c | |||
e4019ebec8 | |||
89c0a7918a | |||
6b5d888db3 | |||
0fddf50245 | |||
251bfc7def | |||
dd4949e78e | |||
0d0e3ae0ff | |||
b3a980f079 | |||
ab946bb711 | |||
120e57cc5c | |||
f1080bfd0f | |||
8190188a05 | |||
a48f080605 | |||
1acfcaa830 |
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(libdatachannel
|
||||
VERSION 0.12.2
|
||||
VERSION 0.13.3
|
||||
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 libdatachannel-config
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
install(FILES ${LIBDATACHANNEL_HEADERS}
|
||||
DESTINATION include/rtc
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT libdatachannel-config
|
||||
NAMESPACE LibDatachannel::
|
||||
DESTINATION share/cmake/libdatachannel
|
||||
)
|
||||
|
||||
# Tests
|
||||
if(NOT NO_TESTS)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
|
1
DOC.md
1
DOC.md
@ -86,6 +86,7 @@ Arguments:
|
||||
- `config`: the configuration structure, containing:
|
||||
- `iceServers` (optional): an array of pointers on null-terminated ice server URIs (NULL if unused)
|
||||
- `iceServersCount` (optional): number of URLs in the array pointed by `iceServers` (0 if unused)
|
||||
- `bindAddress` (optional): if non-NULL, bind only to the given local address (ignored with libnice as ICE backend)
|
||||
- `certificateType` (optional): certificate type, either `RTC_CERTIFICATE_ECDSA` or `RTC_CERTIFICATE_RSA` (0 or `RTC_CERTIFICATE_DEFAULT` if default)
|
||||
- `enableIceTcp`: if true, generate TCP candidates for ICE (ignored with libjuice as ICE backend)
|
||||
- `disableAutoNegotiation`: if true, the user is responsible for calling `rtcSetLocalDescription` after creating a Data Channel and after setting the remote description
|
||||
|
@ -1,4 +1,4 @@
|
||||
# libdatachannel - C/C++ WebRTC Data Channels
|
||||
# libdatachannel - C/C++ WebRTC lightweight library
|
||||
|
||||
libdatachannel is a standalone implementation of WebRTC Data Channels, WebRTC Media Transport, and WebSockets in C++17 with C bindings for POSIX platforms (including GNU/Linux, Android, and Apple macOS) and Microsoft Windows.
|
||||
|
||||
|
2
deps/libjuice
vendored
2
deps/libjuice
vendored
Submodule deps/libjuice updated: f9720541ae...15d6654262
@ -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:
|
||||
|
@ -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 desired amount 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
|
||||
```
|
@ -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,14 +190,17 @@ 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";
|
||||
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);
|
||||
|
||||
dc->onOpen([id, wdc = make_weak_ptr(dc)]() {
|
||||
dc->onOpen([id, wdc = make_weak_ptr(dc), label]() {
|
||||
cout << "DataChannel from " << id << " open" << endl;
|
||||
if (noSend)
|
||||
return;
|
||||
@ -207,7 +212,7 @@ int main(int argc, char **argv) try {
|
||||
try {
|
||||
while (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;
|
||||
@ -215,7 +220,7 @@ int main(int argc, char **argv) try {
|
||||
}
|
||||
});
|
||||
|
||||
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc)]() {
|
||||
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc), label]() {
|
||||
if (noSend)
|
||||
return;
|
||||
|
||||
@ -230,7 +235,7 @@ int main(int argc, char **argv) try {
|
||||
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;
|
||||
@ -239,12 +244,13 @@ int main(int argc, char **argv) try {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
for (const auto &[label, dc] : dataChannelMap) {
|
||||
if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) {
|
||||
dc->send(tempMessageData);
|
||||
sentSize += tempMessageData.size();
|
||||
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"
|
||||
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);
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
14
examples/signaling-server-nodejs/package-lock.json
generated
14
examples/signaling-server-nodejs/package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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');
|
||||
|
||||
|
@ -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) { }
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -74,6 +74,7 @@ struct RTC_CPP_EXPORT Configuration {
|
||||
// ICE settings
|
||||
std::vector<IceServer> iceServers;
|
||||
optional<ProxyServer> proxyServer; // libnice only
|
||||
optional<string> bindAddress; // libjuice only, default any
|
||||
|
||||
// Options
|
||||
CertificateType certificateType = CertificateType::Default;
|
||||
|
@ -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);
|
||||
@ -137,12 +144,14 @@ public:
|
||||
|
||||
void removeFormat(const string &fmt);
|
||||
|
||||
void addSSRC(uint32_t ssrc, optional<string> name,
|
||||
optional<string> msid = nullopt, optional<string> trackID = nullopt);
|
||||
void addSSRC(uint32_t ssrc, optional<string> name, optional<string> msid = nullopt,
|
||||
optional<string> trackID = nullopt);
|
||||
void removeSSRC(uint32_t oldSSRC);
|
||||
void replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, optional<string> name,
|
||||
optional<string> msid = nullopt, optional<string> trackID = nullopt);
|
||||
bool hasSSRC(uint32_t ssrc);
|
||||
std::vector<uint32_t> getSSRCs();
|
||||
std::optional<std::string> getCNameForSsrc(uint32_t ssrc);
|
||||
|
||||
void setBitrate(int bitrate);
|
||||
int getBitrate() const;
|
||||
@ -174,6 +183,8 @@ public:
|
||||
void setMLine(string_view view);
|
||||
};
|
||||
|
||||
void addRTPMap(const RTPMap &map);
|
||||
|
||||
std::map<int, RTPMap>::iterator beginMaps();
|
||||
std::map<int, RTPMap>::iterator endMaps();
|
||||
std::map<int, RTPMap>::iterator removeMap(std::map<int, RTPMap>::iterator iterator);
|
||||
@ -188,33 +199,25 @@ public:
|
||||
|
||||
std::map<int, RTPMap> mRtpMap;
|
||||
std::vector<uint32_t> mSsrcs;
|
||||
|
||||
public:
|
||||
void addRTPMap(const RTPMap &map);
|
||||
|
||||
void removeSSRC(uint32_t oldSSRC);
|
||||
std::map<uint32_t, string> mCNameMap;
|
||||
};
|
||||
|
||||
class RTC_CPP_EXPORT Audio : public Media {
|
||||
public:
|
||||
Audio(string mid = "audio", Direction dir = Direction::SendOnly);
|
||||
|
||||
void addAudioCodec(int payloadType, string codec,
|
||||
optional<string> profile = std::nullopt);
|
||||
void addAudioCodec(int payloadType, string codec, optional<string> profile = std::nullopt);
|
||||
|
||||
void addOpusCodec(int payloadType,
|
||||
optional<string> profile = DEFAULT_OPUS_AUDIO_PROFILE);
|
||||
void addOpusCodec(int payloadType, optional<string> profile = DEFAULT_OPUS_AUDIO_PROFILE);
|
||||
};
|
||||
|
||||
class RTC_CPP_EXPORT Video : public Media {
|
||||
public:
|
||||
Video(string mid = "video", Direction dir = Direction::SendOnly);
|
||||
|
||||
void addVideoCodec(int payloadType, string codec,
|
||||
optional<string> profile = std::nullopt);
|
||||
void addVideoCodec(int payloadType, string codec, optional<string> profile = std::nullopt);
|
||||
|
||||
void addH264Codec(int payloadType,
|
||||
optional<string> profile = DEFAULT_H264_VIDEO_PROFILE);
|
||||
void addH264Codec(int payloadType, optional<string> profile = DEFAULT_H264_VIDEO_PROFILE);
|
||||
void addVP8Codec(int payloadType);
|
||||
void addVP9Codec(int payloadType);
|
||||
};
|
||||
|
71
include/rtc/global.hpp
Normal file
71
include/rtc/global.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RTC_GLOBAL_H
|
||||
#define RTC_GLOBAL_H
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
enum class LogLevel { // Don't change, it must match plog severity
|
||||
None = 0,
|
||||
Fatal = 1,
|
||||
Error = 2,
|
||||
Warning = 3,
|
||||
Info = 4,
|
||||
Debug = 5,
|
||||
Verbose = 6
|
||||
};
|
||||
|
||||
typedef std::function<void(LogLevel level, string message)> LogCallback;
|
||||
|
||||
RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr);
|
||||
#ifdef PLOG_DEFAULT_INSTANCE_ID
|
||||
RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
|
||||
#endif
|
||||
|
||||
RTC_CPP_EXPORT void Preload();
|
||||
RTC_CPP_EXPORT void Cleanup();
|
||||
|
||||
struct SctpSettings {
|
||||
// For the following settings, not set means optimized default
|
||||
optional<size_t> recvBufferSize; // in bytes
|
||||
optional<size_t> sendBufferSize; // in bytes
|
||||
optional<size_t> maxChunksOnQueue; // in chunks
|
||||
optional<size_t> initialCongestionWindow; // in MTUs
|
||||
optional<size_t> maxBurst; // in MTUs
|
||||
optional<unsigned int> congestionControlModule; // 0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC
|
||||
optional<std::chrono::milliseconds> delayedSackTime;
|
||||
optional<std::chrono::milliseconds> minRetransmitTimeout;
|
||||
optional<std::chrono::milliseconds> maxRetransmitTimeout;
|
||||
optional<std::chrono::milliseconds> initialRetransmitTimeout;
|
||||
optional<unsigned int> maxRetransmitAttempts;
|
||||
optional<std::chrono::milliseconds> heartbeatInterval;
|
||||
};
|
||||
|
||||
RTC_CPP_EXPORT void SetSctpSettings(SctpSettings s);
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level);
|
||||
|
||||
#endif
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 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
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
enum class LogLevel { // Don't change, it must match plog severity
|
||||
None = 0,
|
||||
Fatal = 1,
|
||||
Error = 2,
|
||||
Warning = 3,
|
||||
Info = 4,
|
||||
Debug = 5,
|
||||
Verbose = 6
|
||||
};
|
||||
|
||||
RTC_CPP_EXPORT void InitLogger(LogLevel level);
|
||||
RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,8 +95,6 @@ typedef enum {
|
||||
RTC_CERTIFICATE_RSA = 2,
|
||||
} rtcCertificateType;
|
||||
|
||||
#if RTC_ENABLE_MEDIA
|
||||
|
||||
typedef enum {
|
||||
// video
|
||||
RTC_CODEC_H264 = 0,
|
||||
@ -114,41 +113,12 @@ typedef enum {
|
||||
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,29 @@ 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;
|
||||
const char *bindAddress; // libjuice only, NULL means any
|
||||
rtcCertificateType certificateType;
|
||||
bool enableIceTcp;
|
||||
bool disableAutoNegotiation;
|
||||
uint16_t portRangeBegin; // 0 means automatic
|
||||
uint16_t portRangeEnd; // 0 means automatic
|
||||
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,10 +186,27 @@ 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,
|
||||
const rtcDataChannelInit *init); // returns dc id
|
||||
RTC_EXPORT int rtcIsOpen(int dc);
|
||||
RTC_EXPORT int rtcDeleteDataChannel(int dc);
|
||||
|
||||
RTC_EXPORT int rtcGetDataChannelStream(int dc);
|
||||
@ -213,108 +215,119 @@ 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);
|
||||
typedef struct {
|
||||
uint32_t ssrc;
|
||||
const char *name; // optional
|
||||
const char *msid; // optional
|
||||
const char *trackId; // optional, track ID used in MSID
|
||||
} rtcSsrcForTypeInit;
|
||||
|
||||
/// 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 H264PacketizationHandler for track
|
||||
RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
|
||||
|
||||
// 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);
|
||||
|
||||
/// Get all available payload types for given codec and stores them in buffer, does nothing if buffer is NULL
|
||||
int rtcGetTrackPayloadTypesForCodec(int tr, const char * ccodec, int * buffer, int size);
|
||||
|
||||
/// Get all SSRCs for given track
|
||||
int rtcGetSsrcsForTrack(int tr, uint32_t * buffer, int count);
|
||||
|
||||
/// Get CName for SSRC
|
||||
int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char * cname, int cnameSize);
|
||||
|
||||
/// Get all SSRCs for given media type in given SDP
|
||||
/// @param mediaType Media type (audio/video)
|
||||
int rtcGetSsrcsForType(const char * mediaType, const char * sdp, uint32_t * buffer, int bufferSize);
|
||||
|
||||
/// Set SSRC for given media type in given SDP
|
||||
int rtcSetSsrcForType(const char * mediaType, const char * sdp, char * buffer, const int bufferSize, rtcSsrcForTypeInit * init);
|
||||
|
||||
#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 +335,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 +351,36 @@ 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, < 0 means disabled
|
||||
int minRetransmitTimeoutMs; // in msecs, <= 0 means optimized default
|
||||
int maxRetransmitTimeoutMs; // in msecs, <= 0 means optimized default
|
||||
int initialRetransmitTimeoutMs; // in msecs, <= 0 means optimized default
|
||||
int maxRetransmitAttempts; // number of retransmissions, <= 0 means optimized default
|
||||
int heartbeatIntervalMs; // 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,7 +28,7 @@
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class RTC_CPP_EXPORT RtcpNackResponder: public MediaHandlerElement {
|
||||
class RTC_CPP_EXPORT RtcpNackResponder final: public MediaHandlerElement {
|
||||
|
||||
/// Packet storage
|
||||
class RTC_CPP_EXPORT Storage {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -17,7 +17,8 @@
|
||||
*/
|
||||
|
||||
#include "candidate.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
#include "impl/internals.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@ -92,7 +93,7 @@ void Candidate::parse(string candidate) {
|
||||
{"so", TransportType::TcpSo}};
|
||||
|
||||
const std::array prefixes{"a=", "candidate:"};
|
||||
for (const string &prefix : prefixes)
|
||||
for (string prefix : prefixes)
|
||||
if (match_prefix(candidate, prefix))
|
||||
candidate.erase(0, prefix.size());
|
||||
|
||||
|
652
src/capi.cpp
652
src/capi.cpp
@ -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,34 @@ int copyAndReturn(binary b, char *buffer, int size) {
|
||||
return int(b.size());
|
||||
}
|
||||
|
||||
class plogAppender : public plog::IAppender {
|
||||
public:
|
||||
plogAppender(rtcLogCallbackFunc cb = nullptr) { setCallback(cb); }
|
||||
template<typename T>
|
||||
int copyAndReturn(std::vector<T> b, T *buffer, int size) {
|
||||
if (!buffer)
|
||||
return int(b.size());
|
||||
|
||||
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;
|
||||
};
|
||||
if (size < int(b.size()))
|
||||
return RTC_ERR_TOO_SMALL;
|
||||
std::copy(b.begin(), b.end(), buffer);
|
||||
return int(b.size());
|
||||
}
|
||||
|
||||
#if RTC_ENABLE_MEDIA
|
||||
// function is used in RTC_ENABLE_MEDIA only
|
||||
string lowercased(string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
return str;
|
||||
}
|
||||
#endif // RTC_ENABLE_MEDIA
|
||||
} // 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); }
|
||||
@ -351,15 +308,18 @@ int rtcCreatePeerConnection(const rtcConfiguration *config) {
|
||||
for (int i = 0; i < config->iceServersCount; ++i)
|
||||
c.iceServers.emplace_back(string(config->iceServers[i]));
|
||||
|
||||
c.certificateType = static_cast<CertificateType>(config->certificateType);
|
||||
c.enableIceTcp = config->enableIceTcp;
|
||||
c.disableAutoNegotiation = config->disableAutoNegotiation;
|
||||
if (config->bindAddress)
|
||||
c.bindAddress = string(config->bindAddress);
|
||||
|
||||
if (config->portRangeBegin > 0 || config->portRangeEnd > 0) {
|
||||
c.portRangeBegin = config->portRangeBegin;
|
||||
c.portRangeEnd = config->portRangeEnd;
|
||||
}
|
||||
|
||||
c.certificateType = static_cast<CertificateType>(config->certificateType);
|
||||
c.enableIceTcp = config->enableIceTcp;
|
||||
c.disableAutoNegotiation = config->disableAutoNegotiation;
|
||||
|
||||
if (config->mtu > 0)
|
||||
c.mtu = size_t(config->mtu);
|
||||
|
||||
@ -423,6 +383,12 @@ int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *
|
||||
});
|
||||
}
|
||||
|
||||
int rtcIsOpen(int cid) {
|
||||
return wrap([cid] {
|
||||
return getChannel(cid)->isOpen();
|
||||
});
|
||||
}
|
||||
|
||||
int rtcDeleteDataChannel(int dc) {
|
||||
return wrap([dc] {
|
||||
auto dataChannel = getDataChannel(dc);
|
||||
@ -438,39 +404,35 @@ 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) {
|
||||
auto direction = static_cast<Description::Direction>(init->direction);
|
||||
|
||||
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:
|
||||
@ -479,28 +441,28 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
|
||||
case RTC_CODEC_OPUS:
|
||||
mid = "audio";
|
||||
break;
|
||||
default:
|
||||
mid = "video";
|
||||
break;
|
||||
}
|
||||
|
||||
if (_mid) {
|
||||
mid = string(_mid);
|
||||
}
|
||||
|
||||
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 +472,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 +486,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 +525,240 @@ int rtcGetTrackDescription(int tr, char *buffer, int size) {
|
||||
});
|
||||
}
|
||||
|
||||
#if RTC_ENABLE_MEDIA
|
||||
|
||||
void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid, const char *_trackID) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
int rtcGetTrackPayloadTypesForCodec(int tr, const char * ccodec, int * buffer, int size) {
|
||||
return wrap([&] {
|
||||
auto track = getTrack(tr);
|
||||
auto codec = lowercased(string(ccodec));
|
||||
auto description = track->description();
|
||||
std::vector<int> payloadTypes{};
|
||||
payloadTypes.reserve(std::max(size, 0));
|
||||
for (auto it = description.beginMaps(); it != description.endMaps(); it++) {
|
||||
auto element = *it;
|
||||
if (lowercased(element.second.format) == codec) {
|
||||
payloadTypes.push_back(element.first);
|
||||
}
|
||||
}
|
||||
return copyAndReturn(payloadTypes, buffer, size);
|
||||
});
|
||||
}
|
||||
|
||||
int rtcGetSsrcsForTrack(int tr, uint32_t * buffer, int count) {
|
||||
return wrap([&] {
|
||||
auto track = getTrack(tr);
|
||||
auto ssrcs = track->description().getSSRCs();
|
||||
return copyAndReturn(ssrcs, buffer, count);
|
||||
});
|
||||
}
|
||||
|
||||
int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char * cname, int cnameSize) {
|
||||
return wrap([&] {
|
||||
auto track = getTrack(tr);
|
||||
auto description = track->description();
|
||||
auto optCName = description.getCNameForSsrc(ssrc);
|
||||
if (optCName.has_value()) {
|
||||
return copyAndReturn(optCName.value(), cname, cnameSize);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int rtcGetSsrcsForType(const char * mediaType, const char * sdp, uint32_t * buffer, int bufferSize) {
|
||||
return wrap([&] {
|
||||
auto type = lowercased(string(mediaType));
|
||||
auto oldSDP = string(sdp);
|
||||
auto description = Description(oldSDP, "unspec");
|
||||
auto mediaCount = description.mediaCount();
|
||||
for (unsigned int i = 0; i < mediaCount; i++) {
|
||||
if (std::holds_alternative<Description::Media *>(description.media(i))) {
|
||||
auto media = std::get<Description::Media *>(description.media(i));
|
||||
auto currentMediaType = lowercased(media->type());
|
||||
if (currentMediaType == type) {
|
||||
auto ssrcs = media->getSSRCs();
|
||||
return copyAndReturn(ssrcs, buffer, bufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
int rtcSetSsrcForType(const char * mediaType, const char * sdp, char * buffer, const int bufferSize,
|
||||
rtcSsrcForTypeInit * init) {
|
||||
return wrap([&] {
|
||||
auto type = lowercased(string(mediaType));
|
||||
auto prevSDP = string(sdp);
|
||||
auto description = Description(prevSDP, "unspec");
|
||||
auto mediaCount = description.mediaCount();
|
||||
for (unsigned int i = 0; i < mediaCount; i++) {
|
||||
if (std::holds_alternative<Description::Media *>(description.media(i))) {
|
||||
auto media = std::get<Description::Media *>(description.media(i));
|
||||
auto currentMediaType = lowercased(media->type());
|
||||
if (currentMediaType == type) {
|
||||
setSSRC(media, init->ssrc, init->name, init->msid, init->trackId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return copyAndReturn(string(description), buffer, bufferSize);
|
||||
});
|
||||
}
|
||||
|
||||
#endif // RTC_ENABLE_MEDIA
|
||||
#if RTC_ENABLE_WEBSOCKET
|
||||
|
||||
int rtcCreateWebSocket(const char *url) {
|
||||
return wrap([&] {
|
||||
auto ws = std::make_shared<WebSocket>();
|
||||
@ -748,6 +791,7 @@ int rtcDeleteWebsocket(int ws) {
|
||||
return RTC_ERR_SUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
|
||||
@ -1189,4 +1233,54 @@ 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);
|
||||
else if (settings->delayedSackTimeMs < 0)
|
||||
s.delayedSackTime = std::chrono::milliseconds(0);
|
||||
|
||||
if (settings->minRetransmitTimeoutMs > 0)
|
||||
s.minRetransmitTimeout = std::chrono::milliseconds(settings->minRetransmitTimeoutMs);
|
||||
|
||||
if (settings->maxRetransmitTimeoutMs > 0)
|
||||
s.maxRetransmitTimeout = std::chrono::milliseconds(settings->maxRetransmitTimeoutMs);
|
||||
|
||||
if (settings->initialRetransmitTimeoutMs > 0)
|
||||
s.initialRetransmitTimeout = std::chrono::milliseconds(settings->initialRetransmitTimeoutMs);
|
||||
|
||||
if (settings->maxRetransmitAttempts > 0)
|
||||
s.maxRetransmitAttempts = settings->maxRetransmitAttempts;
|
||||
|
||||
if (settings->heartbeatIntervalMs > 0)
|
||||
s.heartbeatInterval = std::chrono::milliseconds(settings->heartbeatIntervalMs);
|
||||
|
||||
SetSctpSettings(std::move(s));
|
||||
return RTC_ERR_SUCCESS;
|
||||
});
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include "description.hpp"
|
||||
|
||||
#include "impl/internals.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
@ -545,8 +547,11 @@ void Description::Entry::parseSdpLine(string_view line) {
|
||||
mAttributes.emplace_back(line.substr(2));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<string>::iterator Description::Entry::beginAttributes() { return mAttributes.begin(); }
|
||||
|
||||
std::vector<string>::iterator Description::Entry::endAttributes() { return mAttributes.end(); }
|
||||
|
||||
std::vector<string>::iterator
|
||||
Description::Entry::removeAttribute(std::vector<string>::iterator it) {
|
||||
return mAttributes.erase(it);
|
||||
@ -554,10 +559,12 @@ Description::Entry::removeAttribute(std::vector<string>::iterator it) {
|
||||
|
||||
void Description::Media::addSSRC(uint32_t ssrc, optional<string> name, optional<string> msid,
|
||||
optional<string> trackID) {
|
||||
if (name)
|
||||
if (name) {
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + *name);
|
||||
else
|
||||
mCNameMap.emplace(ssrc, *name);
|
||||
} else {
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc));
|
||||
}
|
||||
|
||||
if (msid)
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " msid:" + *msid + " " +
|
||||
@ -566,26 +573,28 @@ void Description::Media::addSSRC(uint32_t ssrc, optional<string> name, optional<
|
||||
mSsrcs.emplace_back(ssrc);
|
||||
}
|
||||
|
||||
void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, optional<string> name,
|
||||
optional<string> msid, optional<string> trackID) {
|
||||
auto it = mAttributes.begin();
|
||||
while (it != mAttributes.end()) {
|
||||
if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) {
|
||||
it = mAttributes.erase(it);
|
||||
} else
|
||||
it++;
|
||||
}
|
||||
addSSRC(ssrc, std::move(name), std::move(msid), std::move(trackID));
|
||||
}
|
||||
|
||||
void Description::Media::removeSSRC(uint32_t oldSSRC) {
|
||||
auto it = mAttributes.begin();
|
||||
while (it != mAttributes.end()) {
|
||||
if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) {
|
||||
if (match_prefix(*it, "ssrc:" + std::to_string(oldSSRC)))
|
||||
it = mAttributes.erase(it);
|
||||
} else
|
||||
it++;
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
auto jt = mSsrcs.begin();
|
||||
while (jt != mSsrcs.end()) {
|
||||
if (*jt == oldSSRC)
|
||||
jt = mSsrcs.erase(jt);
|
||||
else
|
||||
++jt;
|
||||
}
|
||||
}
|
||||
|
||||
void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, optional<string> name,
|
||||
optional<string> msid, optional<string> trackID) {
|
||||
removeSSRC(oldSSRC);
|
||||
addSSRC(ssrc, std::move(name), std::move(msid), std::move(trackID));
|
||||
}
|
||||
|
||||
bool Description::Media::hasSSRC(uint32_t ssrc) {
|
||||
@ -856,7 +865,16 @@ void Description::Media::parseSdpLine(string_view line) {
|
||||
} else if (key == "rtcp-mux") {
|
||||
// always added
|
||||
} else if (key == "ssrc") {
|
||||
mSsrcs.emplace_back(to_integer<uint32_t>(value));
|
||||
auto ssrc = to_integer<uint32_t>(value);
|
||||
if (!hasSSRC(ssrc)) {
|
||||
mSsrcs.emplace_back(ssrc);
|
||||
}
|
||||
auto cnamePos = value.find("cname:");
|
||||
if (cnamePos != string::npos) {
|
||||
auto cname = value.substr(cnamePos + 6);
|
||||
mCNameMap.emplace(ssrc, cname);
|
||||
}
|
||||
mAttributes.emplace_back(attr);
|
||||
} else {
|
||||
Entry::parseSdpLine(line);
|
||||
}
|
||||
@ -873,6 +891,14 @@ void Description::Media::addRTPMap(const Description::Media::RTPMap &map) {
|
||||
|
||||
std::vector<uint32_t> Description::Media::getSSRCs() { return mSsrcs; }
|
||||
|
||||
optional<string> Description::Media::getCNameForSsrc(uint32_t ssrc) {
|
||||
auto it = mCNameMap.find(ssrc);
|
||||
if (it != mCNameMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
std::map<int, Description::Media::RTPMap>::iterator Description::Media::beginMaps() {
|
||||
return mRtpMap.begin();
|
||||
}
|
||||
@ -908,11 +934,16 @@ int Description::Media::RTPMap::parsePT(string_view view) {
|
||||
|
||||
void Description::Media::RTPMap::setMLine(string_view mline) {
|
||||
size_t p = mline.find(' ');
|
||||
if (p == string::npos)
|
||||
throw std::invalid_argument("Invalid m-line");
|
||||
|
||||
this->pt = to_integer<int>(mline.substr(0, p));
|
||||
|
||||
string_view line = mline.substr(p + 1);
|
||||
size_t spl = line.find('/');
|
||||
if (spl == string::npos)
|
||||
throw std::invalid_argument("Invalid m-line");
|
||||
|
||||
this->format = line.substr(0, spl);
|
||||
|
||||
line = line.substr(spl + 1);
|
||||
@ -969,7 +1000,7 @@ string Description::typeToString(Type type) {
|
||||
} // namespace rtc
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const rtc::Description &description) {
|
||||
return out << std::string(description);
|
||||
return out << string(description);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, rtc::Description::Type type) {
|
||||
@ -978,18 +1009,17 @@ std::ostream &operator<<(std::ostream &out, rtc::Description::Type type) {
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, rtc::Description::Role role) {
|
||||
using Role = rtc::Description::Role;
|
||||
const char *str;
|
||||
// Used for SDP generation, do not change
|
||||
switch (role) {
|
||||
case Role::Active:
|
||||
str = "active";
|
||||
out << "active";
|
||||
break;
|
||||
case Role::Passive:
|
||||
str = "passive";
|
||||
out << "passive";
|
||||
break;
|
||||
default:
|
||||
str = "actpass";
|
||||
out << "actpass";
|
||||
break;
|
||||
}
|
||||
return out << str;
|
||||
return out;
|
||||
}
|
||||
|
123
src/global.cpp
Normal file
123
src/global.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2021 Paul-Louis Ageneau
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "plog/Appenders/ColorConsoleAppender.h"
|
||||
#include "plog/Formatters/FuncMessageFormatter.h"
|
||||
#include "plog/Formatters/TxtFormatter.h"
|
||||
#include "plog/Init.h"
|
||||
#include "plog/Log.h"
|
||||
#include "plog/Logger.h"
|
||||
//
|
||||
#include "global.hpp"
|
||||
|
||||
#include "impl/init.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
|
||||
struct LogAppender : public plog::IAppender {
|
||||
synchronized_callback<LogLevel, string> callback;
|
||||
|
||||
void write(const plog::Record &record) override {
|
||||
const auto severity = record.getSeverity();
|
||||
auto formatted = plog::FuncMessageFormatter::format(record);
|
||||
formatted.pop_back(); // remove newline
|
||||
|
||||
#ifdef _WIN32
|
||||
using convert_type = std::codecvt_utf8<wchar_t>;
|
||||
std::wstring_convert<convert_type, wchar_t> converter;
|
||||
std::string str = converter.to_bytes(formatted);
|
||||
#else
|
||||
std::string str = formatted;
|
||||
#endif
|
||||
|
||||
if (!callback(static_cast<LogLevel>(severity), str))
|
||||
std::cout << plog::severityToString(severity) << " " << str << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void InitLogger(LogLevel level, LogCallback callback) {
|
||||
static unique_ptr<LogAppender> appender;
|
||||
const auto severity = static_cast<plog::Severity>(level);
|
||||
if (appender) {
|
||||
appender->callback = std::move(callback);
|
||||
InitLogger(severity, nullptr); // change the severity
|
||||
} else if (callback) {
|
||||
appender = std::make_unique<LogAppender>();
|
||||
appender->callback = std::move(callback);
|
||||
InitLogger(severity, appender.get());
|
||||
} else {
|
||||
InitLogger(severity, nullptr); // log to cout
|
||||
}
|
||||
}
|
||||
|
||||
void InitLogger(plog::Severity severity, plog::IAppender *appender) {
|
||||
static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
|
||||
static plog::Logger<0> *logger = nullptr;
|
||||
static std::mutex mutex;
|
||||
std::lock_guard lock(mutex);
|
||||
if (!logger) {
|
||||
logger = &plog::init(severity, appender ? appender : &consoleAppender);
|
||||
PLOG_DEBUG << "Logger initialized";
|
||||
} else {
|
||||
logger->setMaxSeverity(severity);
|
||||
if (appender)
|
||||
logger->addAppender(appender);
|
||||
}
|
||||
}
|
||||
|
||||
void Preload() { Init::Preload(); }
|
||||
void Cleanup() { Init::Cleanup(); }
|
||||
|
||||
void SetSctpSettings(SctpSettings s) { Init::SetSctpSettings(std::move(s)); }
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::LogLevel level) {
|
||||
switch (level) {
|
||||
case rtc::LogLevel::Fatal:
|
||||
out << "fatal";
|
||||
break;
|
||||
case rtc::LogLevel::Error:
|
||||
out << "error";
|
||||
break;
|
||||
case rtc::LogLevel::Warning:
|
||||
out << "warning";
|
||||
break;
|
||||
case rtc::LogLevel::Info:
|
||||
out << "info";
|
||||
break;
|
||||
case rtc::LogLevel::Debug:
|
||||
out << "debug";
|
||||
break;
|
||||
case rtc::LogLevel::Verbose:
|
||||
out << "verbose";
|
||||
break;
|
||||
default:
|
||||
out << "none";
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "sctptransport.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace rtc::impl {
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "dtlstransport.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "internals.hpp"
|
||||
#include "icetransport.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "icetransport.hpp"
|
||||
#include "configuration.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "internals.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
#include <iostream>
|
||||
@ -131,6 +131,11 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
|
||||
jconfig.turn_servers = k > 0 ? turn_servers : nullptr;
|
||||
jconfig.turn_servers_count = k;
|
||||
|
||||
// Bind address
|
||||
if (config.bindAddress) {
|
||||
jconfig.bind_address = config.bindAddress->c_str();
|
||||
}
|
||||
|
||||
// Port range
|
||||
if (config.portRangeBegin > 1024 ||
|
||||
(config.portRangeEnd != 0 && config.portRangeEnd != 65535)) {
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
@ -16,11 +16,27 @@
|
||||
* 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
|
@ -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"
|
||||
@ -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);
|
||||
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -18,13 +18,16 @@
|
||||
|
||||
#include "sctptransport.hpp"
|
||||
#include "dtlstransport.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "internals.hpp"
|
||||
#include "logcounter.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <shared_mutex>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
// RFC 8831: SCTP MUST support performing Path MTU discovery without relying on ICMP or ICMPv6 as
|
||||
@ -54,6 +57,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,
|
||||
@ -64,35 +87,84 @@ static LogCounter
|
||||
static LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning,
|
||||
"Number of SCTP packets received with a bad status");
|
||||
|
||||
std::unordered_set<SctpTransport *> SctpTransport::Instances;
|
||||
std::shared_mutex SctpTransport::InstancesMutex;
|
||||
class SctpTransport::InstancesSet {
|
||||
public:
|
||||
void insert(SctpTransport *instance) {
|
||||
std::unique_lock lock(mMutex);
|
||||
mSet.insert(instance);
|
||||
}
|
||||
|
||||
void erase(SctpTransport *instance) {
|
||||
std::unique_lock lock(mMutex);
|
||||
mSet.erase(instance);
|
||||
}
|
||||
|
||||
using shared_lock = std::shared_lock<std::shared_mutex>;
|
||||
optional<shared_lock> lock(SctpTransport *instance) {
|
||||
shared_lock lock(mMutex);
|
||||
return mSet.find(instance) != mSet.end() ? std::make_optional(std::move(lock)) : nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<SctpTransport *> mSet;
|
||||
std::shared_mutex mMutex;
|
||||
};
|
||||
|
||||
SctpTransport::InstancesSet *SctpTransport::Instances = new InstancesSet;
|
||||
|
||||
void SctpTransport::Init() {
|
||||
usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
|
||||
usrsctp_sysctl_set_sctp_ecn_enable(0);
|
||||
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
|
||||
usrsctp_sysctl_set_sctp_rto_min_default(1 * 1000); // ms
|
||||
usrsctp_sysctl_set_sctp_rto_max_default(10 * 1000); // ms
|
||||
usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms
|
||||
usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms
|
||||
usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
|
||||
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_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);
|
||||
// Reduce SACK delay to 20ms by default (the recommended default value from RFC 4960 is 200ms)
|
||||
usrsctp_sysctl_set_sctp_delayed_sack_time_default(
|
||||
to_uint32(s.delayedSackTime.value_or(20ms).count()));
|
||||
|
||||
// Increase the initial window size to 10 MTUs (RFC 6928)
|
||||
usrsctp_sysctl_set_sctp_initial_cwnd(10);
|
||||
// RTO settings
|
||||
// RFC 2988 recommends a 1s min RTO, which is very high, but TCP on Linux has a 200ms min RTO
|
||||
usrsctp_sysctl_set_sctp_rto_min_default(
|
||||
to_uint32(s.minRetransmitTimeout.value_or(200ms).count()));
|
||||
// Set only 10s as max RTO instead of 60s for shorter connection timeout
|
||||
usrsctp_sysctl_set_sctp_rto_max_default(
|
||||
to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count()));
|
||||
usrsctp_sysctl_set_sctp_init_rto_max_default(
|
||||
to_uint32(s.maxRetransmitTimeout.value_or(10000ms).count()));
|
||||
// Still set 1s as initial RTO
|
||||
usrsctp_sysctl_set_sctp_rto_initial_default(
|
||||
to_uint32(s.initialRetransmitTimeout.value_or(1000ms).count()));
|
||||
|
||||
// Reduce SACK delay from the default 200ms to 20ms
|
||||
usrsctp_sysctl_set_sctp_delayed_sack_time_default(20); // ms
|
||||
// RTX settings
|
||||
// 5 retransmissions instead of 8 to shorten the backoff for shorter connection timeout
|
||||
auto maxRtx = to_uint32(s.maxRetransmitAttempts.value_or(5));
|
||||
usrsctp_sysctl_set_sctp_init_rtx_max_default(maxRtx);
|
||||
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(maxRtx);
|
||||
usrsctp_sysctl_set_sctp_path_rtx_max_default(maxRtx); // single path
|
||||
|
||||
// Heartbeat interval
|
||||
usrsctp_sysctl_set_sctp_heartbeat_interval_default(
|
||||
to_uint32(s.heartbeatInterval.value_or(10000ms).count()));
|
||||
}
|
||||
|
||||
void SctpTransport::Cleanup() {
|
||||
@ -111,10 +183,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
|
||||
PLOG_DEBUG << "Initializing SCTP transport";
|
||||
|
||||
usrsctp_register_address(this);
|
||||
{
|
||||
std::unique_lock lock(InstancesMutex);
|
||||
Instances.insert(this);
|
||||
}
|
||||
Instances->insert(this);
|
||||
|
||||
mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, nullptr, nullptr, 0, nullptr);
|
||||
if (!mSock)
|
||||
@ -195,7 +264,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 +291,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));
|
||||
}
|
||||
@ -243,10 +322,7 @@ SctpTransport::~SctpTransport() {
|
||||
close();
|
||||
|
||||
usrsctp_deregister_address(this);
|
||||
{
|
||||
std::unique_lock lock(InstancesMutex);
|
||||
Instances.erase(this);
|
||||
}
|
||||
Instances->erase(this);
|
||||
}
|
||||
|
||||
void SctpTransport::start() {
|
||||
@ -336,7 +412,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 +429,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) {
|
||||
@ -374,9 +450,6 @@ void SctpTransport::incoming(message_ptr message) {
|
||||
|
||||
PLOG_VERBOSE << "Incoming size=" << message->size();
|
||||
|
||||
// TODO: There seems to be a possible data race between usrsctp_sendv() and usrsctp_conninput()
|
||||
// As a mitigation, lock the send mutex before calling usrsctp_conninput()
|
||||
std::lock_guard lock(mSendMutex);
|
||||
usrsctp_conninput(this, message->data(), message->size(), 0);
|
||||
}
|
||||
|
||||
@ -458,7 +531,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 +584,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 +621,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
|
||||
@ -809,10 +882,7 @@ optional<milliseconds> SctpTransport::rtt() {
|
||||
void SctpTransport::UpcallCallback(struct socket *, void *arg, int /* flags */) {
|
||||
auto *transport = static_cast<SctpTransport *>(arg);
|
||||
|
||||
std::shared_lock lock(InstancesMutex);
|
||||
if (Instances.find(transport) == Instances.end())
|
||||
return;
|
||||
|
||||
if (auto lock = Instances->lock(transport))
|
||||
transport->handleUpcall();
|
||||
}
|
||||
|
||||
@ -821,11 +891,10 @@ int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos,
|
||||
|
||||
// Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket
|
||||
// https://github.com/sctplab/usrsctp/issues/405
|
||||
std::shared_lock lock(InstancesMutex);
|
||||
if (Instances.find(transport) == Instances.end())
|
||||
return -1;
|
||||
|
||||
if (auto lock = Instances->lock(transport))
|
||||
return transport->handleWrite(static_cast<byte *>(data), len, tos, set_df);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace rtc::impl
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "usrsctp.h"
|
||||
|
||||
@ -39,6 +37,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 +82,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);
|
||||
|
||||
@ -119,8 +118,8 @@ private:
|
||||
static void UpcallCallback(struct socket *sock, void *arg, int flags);
|
||||
static int WriteCallback(void *sctp_ptr, void *data, size_t len, uint8_t tos, uint8_t set_df);
|
||||
|
||||
static std::unordered_set<SctpTransport *> Instances;
|
||||
static std::shared_mutex InstancesMutex;
|
||||
class InstancesSet;
|
||||
static InstancesSet *Instances;
|
||||
};
|
||||
|
||||
} // namespace rtc::impl
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "tcptransport.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "internals.hpp"
|
||||
|
||||
#if RTC_ENABLE_WEBSOCKET
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "common.hpp"
|
||||
#include "init.hpp"
|
||||
#include "internals.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#include "tls.hpp"
|
||||
|
||||
#include "internals.hpp"
|
||||
|
||||
#if USE_GNUTLS
|
||||
|
||||
namespace rtc::gnutls {
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "track.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "internals.hpp"
|
||||
#include "logcounter.hpp"
|
||||
#include "peerconnection.hpp"
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define RTC_IMPL_TRANSPORT_H
|
||||
|
||||
#include "common.hpp"
|
||||
#include "internals.hpp"
|
||||
#include "message.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
@ -19,7 +19,7 @@
|
||||
#if RTC_ENABLE_WEBSOCKET
|
||||
|
||||
#include "websocket.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "internals.hpp"
|
||||
#include "common.hpp"
|
||||
#include "threadpool.hpp"
|
||||
|
||||
|
47
src/log.cpp
47
src/log.cpp
@ -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
|
@ -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) { }
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
600
src/rtp.cpp
Normal 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
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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>
|
||||
|
||||
|
@ -122,11 +122,10 @@ 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
|
||||
});
|
||||
|
||||
dc1->onBufferedAmountLow([wdc1 = make_weak_ptr(dc1), &messageData]() {
|
||||
auto dc1 = wdc1.lock();
|
||||
if (!dc1)
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
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)) {
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user