mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-23 15:48:03 +00:00
Compare commits
53 Commits
Author | SHA1 | Date | |
---|---|---|---|
9457492169 | |||
384c84e8aa | |||
b315869989 | |||
aea6708d27 | |||
2166386d42 | |||
f88394ab75 | |||
ba7e0e2a35 | |||
fba965b46c | |||
eff0faf6e1 | |||
cd68d1dba7 | |||
ce9fa374d0 | |||
2bf03205cf | |||
07a5591cda | |||
282ca48b12 | |||
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)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
project(libdatachannel
|
project(libdatachannel
|
||||||
VERSION 0.12.3
|
VERSION 0.13.0
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
|
set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
|
||||||
|
|
||||||
@ -43,8 +43,7 @@ set(LIBDATACHANNEL_SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/init.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/log.cpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpreceivingsession.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpreceivingsession.cpp
|
||||||
@ -62,6 +61,7 @@ set(LIBDATACHANNEL_SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerelement.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerelement.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerrootelement.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerrootelement.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -75,8 +75,7 @@ set(LIBDATACHANNEL_HEADERS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandler.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandler.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/init.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/global.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/log.hpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/reliability.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/reliability.hpp
|
||||||
@ -107,6 +106,7 @@ set(LIBDATACHANNEL_IMPL_SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/sctptransport.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/sctptransport.cpp
|
||||||
@ -129,6 +129,8 @@ set(LIBDATACHANNEL_IMPL_HEADERS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/internals.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/queue.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/queue.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.hpp
|
||||||
@ -213,17 +215,17 @@ set_target_properties(datachannel-static PROPERTIES
|
|||||||
VERSION ${PROJECT_VERSION}
|
VERSION ${PROJECT_VERSION}
|
||||||
CXX_STANDARD 17)
|
CXX_STANDARD 17)
|
||||||
|
|
||||||
target_include_directories(datachannel PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
target_include_directories(datachannel PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
|
||||||
target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
|
target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
|
||||||
target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
target_link_libraries(datachannel PUBLIC Threads::Threads plog::plog)
|
target_link_libraries(datachannel PUBLIC Threads::Threads)
|
||||||
target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp)
|
target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp plog::plog)
|
||||||
|
|
||||||
target_include_directories(datachannel-static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
target_include_directories(datachannel-static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
|
target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc)
|
||||||
target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
target_link_libraries(datachannel-static PUBLIC Threads::Threads plog::plog)
|
target_link_libraries(datachannel-static PUBLIC Threads::Threads)
|
||||||
target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp)
|
target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp plog::plog)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(datachannel PUBLIC ws2_32) # winsock2
|
target_link_libraries(datachannel PUBLIC ws2_32) # winsock2
|
||||||
@ -310,9 +312,6 @@ endif()
|
|||||||
add_library(LibDataChannel::LibDataChannel ALIAS datachannel)
|
add_library(LibDataChannel::LibDataChannel ALIAS datachannel)
|
||||||
add_library(LibDataChannel::LibDataChannelStatic ALIAS datachannel-static)
|
add_library(LibDataChannel::LibDataChannelStatic ALIAS datachannel-static)
|
||||||
|
|
||||||
install(TARGETS datachannel LIBRARY DESTINATION lib)
|
|
||||||
install(FILES ${LIBDATACHANNEL_HEADERS} DESTINATION include/rtc)
|
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
target_compile_options(datachannel PRIVATE -Wall -Wextra)
|
target_compile_options(datachannel PRIVATE -Wall -Wextra)
|
||||||
target_compile_options(datachannel-static PRIVATE -Wall -Wextra)
|
target_compile_options(datachannel-static PRIVATE -Wall -Wextra)
|
||||||
@ -328,6 +327,22 @@ if(WARNINGS_AS_ERRORS)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS datachannel EXPORT datachannel-export
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES ${LIBDATACHANNEL_HEADERS}
|
||||||
|
DESTINATION include/rtc
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT datachannel-export
|
||||||
|
NAMESPACE LibDatachannel::
|
||||||
|
DESTINATION share/cmake/libdatachannel
|
||||||
|
)
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
if(NOT NO_TESTS)
|
if(NOT NO_TESTS)
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||||
|
2
deps/libjuice
vendored
2
deps/libjuice
vendored
Submodule deps/libjuice updated: f9720541ae...43933459d4
@ -10,6 +10,7 @@ This directory contains different WebRTC clients and compatible WebSocket + JSON
|
|||||||
- [signaling-server-rust](signaling-server-rust) contains a similar signaling server in Rust (see [lerouxrgd/datachannel-rs](https://github.com/lerouxrgd/datachannel-rs) for Rust wrappers)
|
- [signaling-server-rust](signaling-server-rust) contains a similar signaling server in Rust (see [lerouxrgd/datachannel-rs](https://github.com/lerouxrgd/datachannel-rs) for Rust wrappers)
|
||||||
|
|
||||||
- [media](media) is a copy/paste demo to send the webcam from your browser into gstreamer.
|
- [media](media) is a copy/paste demo to send the webcam from your browser into gstreamer.
|
||||||
|
- [sfu-media](sfu-media) is a copy/paste SFU demo to relay the webcam between browsers.
|
||||||
- [streamer](streamer) streams h264 and opus samples to web browsers (signaling-server-python is required).
|
- [streamer](streamer) streams h264 and opus samples to web browsers (signaling-server-python is required).
|
||||||
|
|
||||||
Additionally, it contains two debugging tools for libdatachannel with copy-pasting as signaling:
|
Additionally, it contains two debugging tools for libdatachannel with copy-pasting as signaling:
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
# libdatachannel - client-benchmark
|
# libdatachannel - client-benchmark
|
||||||
|
|
||||||
This directory contains a native client to open Data Channels with WebSocket signaling using libdatachannel and benchmark functionalities. It offers two functionalities;
|
This directory contains a native client to open Data Channels with WebSocket signaling using libdatachannel and benchmark functionalities. It offers three functionalities;
|
||||||
- Benchmark: Bi-directional data transfer benchmark (Also supports One-Way testing)
|
- Benchmark: Bi-directional data transfer benchmark (Also supports One-Way testing)
|
||||||
- Constant Throughput Set: Send desired amount of data per second
|
- Constant Throughput Set: Send desired amount of data per second
|
||||||
|
- Multiple Data Channel: Create desried count of data channel
|
||||||
|
|
||||||
## Start Signaling Server
|
## Start Signaling Server
|
||||||
- Start one of the signaling server from the examples folder. For example start `signaling-server-nodejs` like;
|
- Start one of the signaling server from the examples folder. For example start `signaling-server-nodejs` like;
|
||||||
@ -12,7 +13,7 @@ This directory contains a native client to open Data Channels with WebSocket sig
|
|||||||
|
|
||||||
## Start `client-benchmark` Applications
|
## Start `client-benchmark` Applications
|
||||||
|
|
||||||
Start 2 applications by using example calls below. Than copy one of the client's ID and paste to the other peer's screen to start offering process.
|
Start 2 applications by using example calls below. Then copy one of the client's ID and paste to the other peer's screen to start offering process.
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
@ -23,63 +24,90 @@ Start 2 applications by using example calls below. Than copy one of the client's
|
|||||||
Example Output (Offering Peer's Output);
|
Example Output (Offering Peer's Output);
|
||||||
```bash
|
```bash
|
||||||
Stun server is stun:stun.l.google.com:19302
|
Stun server is stun:stun.l.google.com:19302
|
||||||
The local ID is: EQmF
|
The local ID is: H1E3
|
||||||
Url is ws://localhost:8000/EQmF
|
Url is ws://localhost:8000/H1E3
|
||||||
Waiting for signaling to be connected...
|
Waiting for signaling to be connected...
|
||||||
2021-03-25 14:21:58.045 INFO [21386] [rtc::impl::TcpTransport::connect@159] Connected to localhost:8000
|
2021-04-10 19:51:31.319 INFO [16449] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
|
||||||
2021-03-25 14:21:58.045 INFO [21386] [rtc::impl::TcpTransport::runLoop@327] TCP connected
|
2021-04-10 19:51:31.319 INFO [16449] [rtc::impl::TcpTransport::runLoop@331] TCP connected
|
||||||
2021-03-25 14:21:58.046 INFO [21386] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
2021-04-10 19:51:31.321 INFO [16449] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
||||||
WebSocket connected, signaling ready
|
WebSocket connected, signaling ready
|
||||||
Enter a remote ID to send an offer:
|
Enter a remote ID to send an offer:
|
||||||
0tDf
|
n790
|
||||||
Offering to 0tDf
|
Offering to n790
|
||||||
Creating DataChannel with label "benchmark"
|
Creating DataChannel with label "DC-1"
|
||||||
2021-03-25 14:22:07.972 INFO [21379] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
2021-04-10 19:51:32.464 INFO [16442] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
||||||
2021-03-25 14:22:07.973 INFO [21379] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to new
|
2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
|
||||||
2021-03-25 14:22:07.973 INFO [21379] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress
|
2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
|
||||||
Gathering State: in-progress
|
Gathering State: in-progress
|
||||||
2021-03-25 14:22:07.974 INFO [21379] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
2021-04-10 19:51:32.465 INFO [16442] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
||||||
2021-03-25 14:22:07.974 WARN [21379] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:239: Local description already has the maximum number of host candidates
|
|
||||||
Benchmark will run for 300 seconds
|
Benchmark will run for 300 seconds
|
||||||
2021-03-25 14:22:07.976 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
2021-04-10 19:51:32.466 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
||||||
2021-03-25 14:22:07.976 INFO [21396] [rtc::impl::PeerConnection::changeState@964] Changed state to connecting
|
2021-04-10 19:51:32.466 INFO [16450] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
|
||||||
State: connecting
|
State: connecting
|
||||||
2021-03-25 14:22:08.055 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
2021-04-10 19:51:32.489 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
||||||
2021-03-25 14:22:08.055 INFO [21386] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to connecting
|
2021-04-10 19:51:32.489 INFO [16449] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
|
||||||
2021-03-25 14:22:08.105 WARN [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101
|
2021-04-10 19:51:32.490 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
||||||
2021-03-25 14:22:08.105 WARN [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101
|
2021-04-10 19:51:32.491 INFO [16453] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
||||||
2021-03-25 14:22:08.105 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed
|
2021-04-10 19:51:32.497 INFO [16443] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
|
||||||
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful
|
2021-04-10 19:51:32.497 INFO [16443] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
|
||||||
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done
|
|
||||||
2021-03-25 14:22:08.107 INFO [21396] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete
|
|
||||||
Gathering State: complete
|
|
||||||
2021-03-25 14:22:08.155 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
|
||||||
2021-03-25 14:22:08.206 INFO [21396] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
|
||||||
#1 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
|
|
||||||
2021-03-25 14:22:09.059 INFO [21399] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
|
||||||
2021-03-25 14:22:09.069 INFO [21382] [rtc::impl::SctpTransport::processNotification@708] SCTP connected
|
|
||||||
2021-03-25 14:22:09.069 INFO [21382] [rtc::impl::PeerConnection::changeState@964] Changed state to connected
|
|
||||||
State: connected
|
State: connected
|
||||||
DataChannel from 0tDf open
|
DataChannel from n790 open
|
||||||
#2 Received: 41488 KB/s Sent: 42465 KB/s BufferSize: 65535
|
2021-04-10 19:51:32.542 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
|
||||||
#3 Received: 43925 KB/s Sent: 43729 KB/s BufferSize: 65535
|
2021-04-10 19:51:32.589 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
||||||
#4 Received: 42491 KB/s Sent: 42361 KB/s BufferSize: 65535
|
#1
|
||||||
#5 Received: 45878 KB/s Sent: 45682 KB/s BufferSize: 65535
|
DC-1 Received: 40789 KB/s Sent: 41180 KB/s BufferSize: 65535
|
||||||
Stats# Received Total: 174 MB Sent Total: 175 MB RTT: 17 ms
|
TOTL Received: 40789 KB/s Sent: 41180 KB/s
|
||||||
|
2021-04-10 19:51:34.039 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
|
||||||
|
2021-04-10 19:51:34.039 INFO [16450] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
|
||||||
|
2021-04-10 19:51:34.039 INFO [16450] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
|
||||||
|
Gathering State: complete
|
||||||
|
#2
|
||||||
|
DC-1 Received: 41709 KB/s Sent: 41774 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 41709 KB/s Sent: 41774 KB/s
|
||||||
|
#3
|
||||||
|
DC-1 Received: 42165 KB/s Sent: 42360 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 42165 KB/s Sent: 42360 KB/s
|
||||||
|
#4
|
||||||
|
DC-1 Received: 42880 KB/s Sent: 42750 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 42880 KB/s Sent: 42750 KB/s
|
||||||
|
#5
|
||||||
|
DC-1 Received: 41771 KB/s Sent: 42097 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 41771 KB/s Sent: 42097 KB/s
|
||||||
|
Stats# Received Total: 210 MB Sent Total: 211 MB RTT: 20 ms
|
||||||
|
|
||||||
#6 Received: 43665 KB/s Sent: 43599 KB/s BufferSize: 65535
|
#6
|
||||||
#7 Received: 45749 KB/s Sent: 45488 KB/s BufferSize: 65535
|
DC-1 Received: 46235 KB/s Sent: 30433 KB/s BufferSize: 65535
|
||||||
#8 Received: 44055 KB/s Sent: 44055 KB/s BufferSize: 65535
|
TOTL Received: 46235 KB/s Sent: 30433 KB/s
|
||||||
#9 Received: 21572 KB/s Sent: 58199 KB/s BufferSize: 65535
|
#7
|
||||||
#10 Received: 22940 KB/s Sent: 55005 KB/s BufferSize: 65535
|
DC-1 Received: 47116 KB/s Sent: 28413 KB/s BufferSize: 65535
|
||||||
Stats# Received Total: 353 MB Sent Total: 422 MB RTT: 15 ms
|
TOTL Received: 47116 KB/s Sent: 28413 KB/s
|
||||||
|
#8
|
||||||
|
DC-1 Received: 46923 KB/s Sent: 32520 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 46923 KB/s Sent: 32520 KB/s
|
||||||
|
#9
|
||||||
|
DC-1 Received: 44513 KB/s Sent: 34020 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 44513 KB/s Sent: 34020 KB/s
|
||||||
|
#10
|
||||||
|
DC-1 Received: 41966 KB/s Sent: 36166 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 41966 KB/s Sent: 36166 KB/s
|
||||||
|
Stats# Received Total: 438 MB Sent Total: 373 MB RTT: 19 ms
|
||||||
|
|
||||||
#11 Received: 27501 KB/s Sent: 53112 KB/s BufferSize: 65535
|
#11
|
||||||
#12 Received: 29914 KB/s Sent: 48162 KB/s BufferSize: 65535
|
DC-1 Received: 42617 KB/s Sent: 39619 KB/s BufferSize: 65535
|
||||||
#13 Received: 31869 KB/s Sent: 45946 KB/s BufferSize: 65535
|
TOTL Received: 42617 KB/s Sent: 39619 KB/s
|
||||||
#14 Received: 22484 KB/s Sent: 53636 KB/s BufferSize: 65535
|
#12
|
||||||
#15 Received: 16294 KB/s Sent: 56833 KB/s BufferSize: 65535
|
DC-1 Received: 43792 KB/s Sent: 43338 KB/s BufferSize: 65535
|
||||||
Stats# Received Total: 482 MB Sent Total: 682 MB RTT: 13 ms
|
TOTL Received: 43792 KB/s Sent: 43338 KB/s
|
||||||
|
#13
|
||||||
|
DC-1 Received: 41715 KB/s Sent: 41585 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 41715 KB/s Sent: 41585 KB/s
|
||||||
|
#14
|
||||||
|
DC-1 Received: 39860 KB/s Sent: 33822 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 39860 KB/s Sent: 33822 KB/s
|
||||||
|
#15
|
||||||
|
DC-1 Received: 47576 KB/s Sent: 25352 KB/s BufferSize: 65535
|
||||||
|
TOTL Received: 47576 KB/s Sent: 25352 KB/s
|
||||||
|
Stats# Received Total: 655 MB Sent Total: 558 MB RTT: 13 ms
|
||||||
```
|
```
|
||||||
|
|
||||||
### Benchmark for 300 seconds (Only Send, One Way)
|
### Benchmark for 300 seconds (Only Send, One Way)
|
||||||
@ -92,64 +120,92 @@ Start second peer as;
|
|||||||
|
|
||||||
Example Output (Offering Peer's Output);
|
Example Output (Offering Peer's Output);
|
||||||
```bash
|
```bash
|
||||||
|
Not Sending data. (One way benchmark).
|
||||||
Stun server is stun:stun.l.google.com:19302
|
Stun server is stun:stun.l.google.com:19302
|
||||||
The local ID is: XLLn
|
The local ID is: 7EaP
|
||||||
Url is ws://localhost:8000/XLLn
|
Url is ws://localhost:8000/7EaP
|
||||||
Waiting for signaling to be connected...
|
Waiting for signaling to be connected...
|
||||||
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::TcpTransport::connect@159] Connected to localhost:8000
|
2021-04-10 19:54:36.857 INFO [16632] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
|
||||||
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::TcpTransport::runLoop@327] TCP connected
|
2021-04-10 19:54:36.857 INFO [16632] [rtc::impl::TcpTransport::runLoop@331] TCP connected
|
||||||
2021-03-25 14:34:24.479 INFO [22332] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
2021-04-10 19:54:36.858 INFO [16632] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
||||||
WebSocket connected, signaling ready
|
WebSocket connected, signaling ready
|
||||||
Enter a remote ID to send an offer:
|
Enter a remote ID to send an offer:
|
||||||
Okt4
|
UDL4
|
||||||
Offering to Okt4
|
Offering to UDL4
|
||||||
Creating DataChannel with label "benchmark"
|
Creating DataChannel with label "DC-1"
|
||||||
2021-03-25 14:34:37.948 INFO [22325] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
2021-04-10 19:54:53.381 INFO [16625] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
||||||
2021-03-25 14:34:37.949 INFO [22325] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to new
|
2021-04-10 19:54:53.382 INFO [16625] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
|
||||||
2021-03-25 14:34:37.949 INFO [22325] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress
|
2021-04-10 19:54:53.382 INFO [16625] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
|
||||||
Gathering State: in-progress
|
Gathering State: in-progress
|
||||||
2021-03-25 14:34:37.950 INFO [22325] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
2021-04-10 19:54:53.383 INFO [16625] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
||||||
2021-03-25 14:34:37.951 WARN [22325] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:239: Local description already has the maximum number of host candidates
|
|
||||||
Benchmark will run for 300 seconds
|
Benchmark will run for 300 seconds
|
||||||
2021-03-25 14:34:37.952 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
2021-04-10 19:54:53.384 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
||||||
2021-03-25 14:34:37.952 INFO [22334] [rtc::impl::PeerConnection::changeState@964] Changed state to connecting
|
2021-04-10 19:54:53.384 INFO [16646] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
|
||||||
State: connecting
|
State: connecting
|
||||||
2021-03-25 14:34:37.969 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
2021-04-10 19:54:53.475 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
||||||
2021-03-25 14:34:37.969 INFO [22332] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to connecting
|
2021-04-10 19:54:53.475 INFO [16632] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
|
||||||
2021-03-25 14:34:37.970 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
2021-04-10 19:54:53.527 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
|
||||||
2021-03-25 14:34:37.971 INFO [22337] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
2021-04-10 19:54:53.575 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
||||||
2021-03-25 14:34:37.977 INFO [22327] [rtc::impl::SctpTransport::processNotification@708] SCTP connected
|
2021-04-10 19:54:53.625 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
||||||
2021-03-25 14:34:37.977 INFO [22327] [rtc::impl::PeerConnection::changeState@964] Changed state to connected
|
#1
|
||||||
|
DC-1 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 0 KB/s Sent: 0 KB/s
|
||||||
|
2021-04-10 19:54:54.481 INFO [16653] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
||||||
|
2021-04-10 19:54:54.491 INFO [16627] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
|
||||||
|
2021-04-10 19:54:54.491 INFO [16627] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
|
||||||
State: connected
|
State: connected
|
||||||
DataChannel from Okt4 open
|
DataChannel from UDL4 open
|
||||||
2021-03-25 14:34:38.019 WARN [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101
|
#2
|
||||||
2021-03-25 14:34:38.019 WARN [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101
|
DC-1 Received: 84326 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
2021-03-25 14:34:38.019 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed
|
TOTL Received: 84326 KB/s Sent: 0 KB/s
|
||||||
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful
|
#3
|
||||||
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done
|
DC-1 Received: 99387 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
2021-03-25 14:34:38.022 INFO [22334] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete
|
TOTL Received: 99387 KB/s Sent: 0 KB/s
|
||||||
|
2021-04-10 19:54:57.025 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
|
||||||
|
2021-04-10 19:54:57.025 INFO [16646] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
|
||||||
|
2021-04-10 19:54:57.025 INFO [16646] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
|
||||||
Gathering State: complete
|
Gathering State: complete
|
||||||
2021-03-25 14:34:38.069 INFO [22334] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
#4
|
||||||
#1 Received: 0 KB/s Sent: 92223 KB/s BufferSize: 65535
|
DC-1 Received: 94871 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
#2 Received: 0 KB/s Sent: 89291 KB/s BufferSize: 65535
|
TOTL Received: 94871 KB/s Sent: 0 KB/s
|
||||||
#3 Received: 0 KB/s Sent: 95087 KB/s BufferSize: 65535
|
#5
|
||||||
#4 Received: 0 KB/s Sent: 101050 KB/s BufferSize: 65535
|
DC-1 Received: 96259 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
#5 Received: 0 KB/s Sent: 99778 KB/s BufferSize: 0
|
TOTL Received: 96259 KB/s Sent: 0 KB/s
|
||||||
Stats# Received Total: 0 MB Sent Total: 480 MB RTT: 8 ms
|
Stats# Received Total: 377 MB Sent Total: 0 MB RTT: 2 ms
|
||||||
|
|
||||||
#6 Received: 0 KB/s Sent: 100366 KB/s BufferSize: 65535
|
#6
|
||||||
#7 Received: 0 KB/s Sent: 101201 KB/s BufferSize: 65535
|
DC-1 Received: 92873 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
#8 Received: 0 KB/s Sent: 100892 KB/s BufferSize: 65535
|
TOTL Received: 92873 KB/s Sent: 0 KB/s
|
||||||
#9 Received: 0 KB/s Sent: 101288 KB/s BufferSize: 65535
|
#7
|
||||||
#10 Received: 0 KB/s Sent: 95676 KB/s BufferSize: 65535
|
DC-1 Received: 87724 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
Stats# Received Total: 0 MB Sent Total: 982 MB RTT: 8 ms
|
TOTL Received: 87724 KB/s Sent: 0 KB/s
|
||||||
|
#8
|
||||||
|
DC-1 Received: 95123 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 95123 KB/s Sent: 0 KB/s
|
||||||
|
#9
|
||||||
|
DC-1 Received: 100022 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 100022 KB/s Sent: 0 KB/s
|
||||||
|
#10
|
||||||
|
DC-1 Received: 98124 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 98124 KB/s Sent: 0 KB/s
|
||||||
|
Stats# Received Total: 853 MB Sent Total: 0 MB RTT: 2 ms
|
||||||
|
|
||||||
#11 Received: 0 KB/s Sent: 96254 KB/s BufferSize: 65535
|
#11
|
||||||
#12 Received: 0 KB/s Sent: 105473 KB/s BufferSize: 65535
|
DC-1 Received: 103628 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
#13 Received: 0 KB/s Sent: 95549 KB/s BufferSize: 65535
|
TOTL Received: 103628 KB/s Sent: 0 KB/s
|
||||||
#14 Received: 0 KB/s Sent: 100366 KB/s BufferSize: 65535
|
#12
|
||||||
#15 Received: 0 KB/s Sent: 101336 KB/s BufferSize: 65535
|
DC-1 Received: 106166 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
Stats# Received Total: 0 MB Sent Total: 1484 MB RTT: 8 ms
|
TOTL Received: 106166 KB/s Sent: 0 KB/s
|
||||||
|
#13
|
||||||
|
DC-1 Received: 98410 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 98410 KB/s Sent: 0 KB/s
|
||||||
|
#14
|
||||||
|
DC-1 Received: 99854 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 99854 KB/s Sent: 0 KB/s
|
||||||
|
#15
|
||||||
|
DC-1 Received: 98487 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 98487 KB/s Sent: 0 KB/s
|
||||||
|
Stats# Received Total: 1362 MB Sent Total: 0 MB RTT: 2 ms
|
||||||
```
|
```
|
||||||
|
|
||||||
### Constant Throughput Set 8000 byte, for 300 seconds, send buffer 10000 byte
|
### Constant Throughput Set 8000 byte, for 300 seconds, send buffer 10000 byte
|
||||||
@ -159,61 +215,249 @@ Stats# Received Total: 0 MB Sent Total: 1484 MB RTT: 8 ms
|
|||||||
Example Output (Offering Peer's Output);
|
Example Output (Offering Peer's Output);
|
||||||
```bash
|
```bash
|
||||||
Stun server is stun:stun.l.google.com:19302
|
Stun server is stun:stun.l.google.com:19302
|
||||||
The local ID is: 1w9O
|
The local ID is: 5zkC
|
||||||
Url is ws://localhost:8000/1w9O
|
Url is ws://localhost:8000/5zkC
|
||||||
Waiting for signaling to be connected...
|
Waiting for signaling to be connected...
|
||||||
2021-03-25 14:29:38.697 INFO [21844] [rtc::impl::TcpTransport::connect@159] Connected to localhost:8000
|
2021-04-10 19:52:49.788 INFO [16530] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
|
||||||
2021-03-25 14:29:38.697 INFO [21844] [rtc::impl::TcpTransport::runLoop@327] TCP connected
|
2021-04-10 19:52:49.788 INFO [16530] [rtc::impl::TcpTransport::runLoop@331] TCP connected
|
||||||
2021-03-25 14:29:38.698 INFO [21844] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
2021-04-10 19:52:49.789 INFO [16530] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
||||||
WebSocket connected, signaling ready
|
WebSocket connected, signaling ready
|
||||||
Enter a remote ID to send an offer:
|
Enter a remote ID to send an offer:
|
||||||
zi4B
|
WawD
|
||||||
Offering to zi4B
|
Offering to WawD
|
||||||
Creating DataChannel with label "benchmark"
|
Creating DataChannel with label "DC-1"
|
||||||
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
2021-04-10 19:52:57.720 INFO [16523] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
||||||
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to new
|
2021-04-10 19:52:57.721 INFO [16523] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
|
||||||
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to in-progress
|
2021-04-10 19:52:57.721 INFO [16523] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
|
||||||
Gathering State: in-progress
|
Gathering State: in-progress
|
||||||
2021-03-25 14:29:48.729 INFO [21837] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
2021-04-10 19:52:57.722 INFO [16523] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
||||||
2021-03-25 14:29:48.730 WARN [21837] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:239: Local description already has the maximum number of host candidates
|
|
||||||
Benchmark will run for 300 seconds
|
Benchmark will run for 300 seconds
|
||||||
2021-03-25 14:29:48.730 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
2021-04-10 19:52:57.722 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
||||||
2021-03-25 14:29:48.731 INFO [21866] [rtc::impl::PeerConnection::changeState@964] Changed state to connecting
|
2021-04-10 19:52:57.722 INFO [16533] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
|
||||||
State: connecting
|
State: connecting
|
||||||
2021-03-25 14:29:48.732 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
2021-04-10 19:52:57.725 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
||||||
2021-03-25 14:29:48.732 INFO [21844] [rtc::impl::PeerConnection::changeSignalingState@992] Changed signaling state to connecting
|
2021-04-10 19:52:57.727 INFO [16530] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
|
||||||
2021-03-25 14:29:48.782 WARN [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:426: Send failed, errno=101
|
2021-04-10 19:52:57.826 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
||||||
2021-03-25 14:29:48.782 WARN [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1483: STUN message send failed, errno=101
|
2021-04-10 19:52:57.828 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
||||||
2021-03-25 14:29:48.782 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN binding failed
|
2021-04-10 19:52:57.829 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
|
||||||
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1302: STUN server binding successful
|
2021-04-10 19:52:57.884 INFO [16535] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
||||||
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2148: Candidate gathering done
|
2021-04-10 19:52:57.907 INFO [16526] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
|
||||||
2021-03-25 14:29:48.787 INFO [21866] [rtc::impl::PeerConnection::changeGatheringState@981] Changed gathering state to complete
|
2021-04-10 19:52:57.907 INFO [16526] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
|
||||||
Gathering State: complete
|
|
||||||
2021-03-25 14:29:48.832 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
|
||||||
2021-03-25 14:29:48.882 INFO [21866] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
|
||||||
2021-03-25 14:29:49.735 INFO [21869] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
|
||||||
2021-03-25 14:29:49.742 INFO [21841] [rtc::impl::SctpTransport::processNotification@708] SCTP connected
|
|
||||||
2021-03-25 14:29:49.742 INFO [21841] [rtc::impl::PeerConnection::changeState@964] Changed state to connected
|
|
||||||
State: connected
|
State: connected
|
||||||
DataChannel from zi4B open
|
DataChannel from WawD open
|
||||||
#1 Received: 0 KB/s Sent: 78 KB/s BufferSize: 0
|
#1
|
||||||
#2 Received: 8002 KB/s Sent: 7999 KB/s BufferSize: 0
|
DC-1 Received: 6515 KB/s Sent: 6577 KB/s BufferSize: 0
|
||||||
#3 Received: 8002 KB/s Sent: 7998 KB/s BufferSize: 0
|
TOTL Received: 6515 KB/s Sent: 6577 KB/s
|
||||||
#4 Received: 7995 KB/s Sent: 8000 KB/s BufferSize: 0
|
#2
|
||||||
#5 Received: 8000 KB/s Sent: 8001 KB/s BufferSize: 0
|
DC-1 Received: 7998 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
Stats# Received Total: 33 MB Sent Total: 33 MB RTT: 0 ms
|
TOTL Received: 7998 KB/s Sent: 7999 KB/s
|
||||||
|
#3
|
||||||
|
DC-1 Received: 7933 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 7933 KB/s Sent: 7999 KB/s
|
||||||
|
2021-04-10 19:53:01.275 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
|
||||||
|
2021-04-10 19:53:01.275 INFO [16533] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
|
||||||
|
2021-04-10 19:53:01.275 INFO [16533] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
|
||||||
|
Gathering State: complete
|
||||||
|
#4
|
||||||
|
DC-1 Received: 8070 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 8070 KB/s Sent: 8000 KB/s
|
||||||
|
#5
|
||||||
|
DC-1 Received: 7984 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 7984 KB/s Sent: 8000 KB/s
|
||||||
|
Stats# Received Total: 39 MB Sent Total: 39 MB RTT: 0 ms
|
||||||
|
|
||||||
#6 Received: 8001 KB/s Sent: 7999 KB/s BufferSize: 0
|
#6
|
||||||
#7 Received: 7997 KB/s Sent: 7998 KB/s BufferSize: 0
|
DC-1 Received: 8004 KB/s Sent: 7998 KB/s BufferSize: 0
|
||||||
#8 Received: 8001 KB/s Sent: 7999 KB/s BufferSize: 0
|
TOTL Received: 8004 KB/s Sent: 7998 KB/s
|
||||||
#9 Received: 7998 KB/s Sent: 8001 KB/s BufferSize: 0
|
#7
|
||||||
#10 Received: 8003 KB/s Sent: 7998 KB/s BufferSize: 0
|
DC-1 Received: 7997 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
Stats# Received Total: 74 MB Sent Total: 74 MB RTT: 0 ms
|
TOTL Received: 7997 KB/s Sent: 8000 KB/s
|
||||||
|
#8
|
||||||
|
DC-1 Received: 8008 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 8008 KB/s Sent: 8000 KB/s
|
||||||
|
#9
|
||||||
|
DC-1 Received: 8007 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 8007 KB/s Sent: 8000 KB/s
|
||||||
|
#10
|
||||||
|
DC-1 Received: 7999 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 7999 KB/s Sent: 7999 KB/s
|
||||||
|
Stats# Received Total: 81 MB Sent Total: 81 MB RTT: 0 ms
|
||||||
|
|
||||||
#11 Received: 7990 KB/s Sent: 7998 KB/s BufferSize: 0
|
#11
|
||||||
#12 Received: 7999 KB/s Sent: 8000 KB/s BufferSize: 0
|
DC-1 Received: 7997 KB/s Sent: 8001 KB/s BufferSize: 0
|
||||||
#13 Received: 8001 KB/s Sent: 8002 KB/s BufferSize: 0
|
TOTL Received: 7997 KB/s Sent: 8001 KB/s
|
||||||
#14 Received: 7998 KB/s Sent: 7999 KB/s BufferSize: 0
|
#12
|
||||||
#15 Received: 8000 KB/s Sent: 7998 KB/s BufferSize: 0
|
DC-1 Received: 7981 KB/s Sent: 7997 KB/s BufferSize: 0
|
||||||
Stats# Received Total: 115 MB Sent Total: 115 MB RTT: 0 ms
|
TOTL Received: 7981 KB/s Sent: 7997 KB/s
|
||||||
|
#13
|
||||||
|
DC-1 Received: 8024 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 8024 KB/s Sent: 8000 KB/s
|
||||||
|
#14
|
||||||
|
DC-1 Received: 7990 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 7990 KB/s Sent: 7999 KB/s
|
||||||
|
#15
|
||||||
|
DC-1 Received: 8001 KB/s Sent: 8002 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 8001 KB/s Sent: 8002 KB/s
|
||||||
|
Stats# Received Total: 122 MB Sent Total: 122 MB RTT: 0 ms
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constant Throughput Set 8000 byte, for 300 seconds, send buffer 10000 byte, 5 Data Channel
|
||||||
|
|
||||||
|
> `./client-benchmark -p -d 300 -r 8000 -b 10000 -c 5`
|
||||||
|
|
||||||
|
Example Output (Offering Peer's Output);
|
||||||
|
```bash
|
||||||
|
Stun server is stun:stun.l.google.com:19302
|
||||||
|
The local ID is: QZ46
|
||||||
|
Url is ws://localhost:8000/QZ46
|
||||||
|
Waiting for signaling to be connected...
|
||||||
|
2021-04-10 19:57:28.562 INFO [17117] [rtc::impl::TcpTransport::connect@163] Connected to localhost:8000
|
||||||
|
2021-04-10 19:57:28.562 INFO [17117] [rtc::impl::TcpTransport::runLoop@331] TCP connected
|
||||||
|
2021-04-10 19:57:28.563 INFO [17117] [rtc::impl::WsTransport::incoming@118] WebSocket open
|
||||||
|
WebSocket connected, signaling ready
|
||||||
|
Enter a remote ID to send an offer:
|
||||||
|
lTZA
|
||||||
|
Offering to lTZA
|
||||||
|
Creating DataChannel with label "DC-1"
|
||||||
|
2021-04-10 19:57:37.371 INFO [17110] [rtc::impl::IceTransport::IceTransport@106] Using STUN server "stun.l.google.com:19302"
|
||||||
|
2021-04-10 19:57:37.372 INFO [17110] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to new
|
||||||
|
2021-04-10 19:57:37.373 INFO [17110] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to in-progress
|
||||||
|
2021-04-10 19:57:37.373 INFO [17110] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to gathering
|
||||||
|
Gathering State: in-progress
|
||||||
|
Creating DataChannel with label "DC-2"
|
||||||
|
2021-04-10 19:57:37.373 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connecting
|
||||||
|
Creating DataChannel with label "DC-3"
|
||||||
|
2021-04-10 19:57:37.374 INFO [17119] [rtc::impl::PeerConnection::changeState@1016] Changed state to connecting
|
||||||
|
Creating DataChannel with label "DC-4"
|
||||||
|
Creating DataChannel with label "DC-5"
|
||||||
|
State: Benchmark will run for connecting300 seconds
|
||||||
|
|
||||||
|
2021-04-10 19:57:37.376 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:610: Using STUN server stun.l.google.com:19302
|
||||||
|
2021-04-10 19:57:37.378 INFO [17117] [rtc::impl::PeerConnection::changeSignalingState@1044] Changed signaling state to connecting
|
||||||
|
2021-04-10 19:57:37.423 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:1328: STUN server binding successful
|
||||||
|
2021-04-10 19:57:37.476 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to connected
|
||||||
|
2021-04-10 19:57:37.478 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:787: Changing state to completed
|
||||||
|
2021-04-10 19:57:38.383 INFO [17122] [rtc::impl::DtlsTransport::runRecvLoop@503] DTLS handshake finished
|
||||||
|
2021-04-10 19:57:38.392 INFO [17113] [rtc::impl::SctpTransport::processNotification@713] SCTP connected
|
||||||
|
2021-04-10 19:57:38.392 INFO [17113] [rtc::impl::PeerConnection::changeState@1016] Changed state to connected
|
||||||
|
State: connected
|
||||||
|
DataChannel from lTZA open
|
||||||
|
DataChannel from lTZA open
|
||||||
|
#DataChannel from lTZA open
|
||||||
|
DataChannel from lTZA open
|
||||||
|
1
|
||||||
|
DC-5 Received: 0 KB/s Sent: 79 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 0 KB/s Sent: 79 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 0 KB/s Sent: 0 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 0 KB/s Sent: 158 KB/s
|
||||||
|
DataChannel from lTZA open
|
||||||
|
#2
|
||||||
|
DC-5 Received: 7960 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 7804 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 7883 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 7882 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 7804 KB/s Sent: 8000 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 39333 KB/s Sent: 40000 KB/s
|
||||||
|
#3
|
||||||
|
DC-5 Received: 7966 KB/s Sent: 7996 KB/s BufferSize: 81504
|
||||||
|
DC-3 Received: 8047 KB/s Sent: 7996 KB/s BufferSize: 81504
|
||||||
|
DC-4 Received: 7958 KB/s Sent: 7996 KB/s BufferSize: 81504
|
||||||
|
DC-2 Received: 7958 KB/s Sent: 7996 KB/s BufferSize: 81504
|
||||||
|
DC-1 Received: 8067 KB/s Sent: 7996 KB/s BufferSize: 163597
|
||||||
|
TOTL Received: 39996 KB/s Sent: 39980 KB/s
|
||||||
|
2021-04-10 19:57:40.926 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:843: STUN server binding failed (timeout)
|
||||||
|
2021-04-10 19:57:40.926 INFO [17119] [rtc::impl::IceTransport::LogCallback@339] juice: agent.c:2206: Candidate gathering done
|
||||||
|
2021-04-10 19:57:40.926 INFO [17119] [rtc::impl::PeerConnection::changeGatheringState@1033] Changed gathering state to complete
|
||||||
|
Gathering State: complete
|
||||||
|
#4
|
||||||
|
DC-5 Received: 7970 KB/s Sent: 8002 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 7957 KB/s Sent: 8002 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 7910 KB/s Sent: 8002 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 7967 KB/s Sent: 8002 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 7957 KB/s Sent: 8002 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 39761 KB/s Sent: 40010 KB/s
|
||||||
|
#5
|
||||||
|
DC-5 Received: 7996 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 8006 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 8078 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 8015 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 7928 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 40023 KB/s Sent: 39995 KB/s
|
||||||
|
Stats# Received Total: 165 MB Sent Total: 166 MB RTT: 1 ms
|
||||||
|
|
||||||
|
#6
|
||||||
|
DC-5 Received: 7968 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 7962 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 7965 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 7970 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 8044 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 39909 KB/s Sent: 39995 KB/s
|
||||||
|
#7
|
||||||
|
DC-5 Received: 6658 KB/s Sent: 8001 KB/s BufferSize: 82228
|
||||||
|
DC-3 Received: 6584 KB/s Sent: 8001 KB/s BufferSize: 163596
|
||||||
|
DC-4 Received: 6572 KB/s Sent: 8001 KB/s BufferSize: 163596
|
||||||
|
DC-2 Received: 6571 KB/s Sent: 8001 KB/s BufferSize: 163596
|
||||||
|
DC-1 Received: 6492 KB/s Sent: 8001 KB/s BufferSize: 163596
|
||||||
|
TOTL Received: 32877 KB/s Sent: 40005 KB/s
|
||||||
|
#8
|
||||||
|
DC-5 Received: 5773 KB/s Sent: 7997 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 6555 KB/s Sent: 7997 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 6164 KB/s Sent: 7997 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 6241 KB/s Sent: 7997 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 5454 KB/s Sent: 7997 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 30187 KB/s Sent: 39985 KB/s
|
||||||
|
#9
|
||||||
|
DC-5 Received: 7442 KB/s Sent: 8002 KB/s BufferSize: 326921
|
||||||
|
DC-3 Received: 7580 KB/s Sent: 8002 KB/s BufferSize: 326921
|
||||||
|
DC-4 Received: 7363 KB/s Sent: 8002 KB/s BufferSize: 326921
|
||||||
|
DC-2 Received: 7524 KB/s Sent: 8002 KB/s BufferSize: 326921
|
||||||
|
DC-1 Received: 7362 KB/s Sent: 8002 KB/s BufferSize: 408769
|
||||||
|
TOTL Received: 37271 KB/s Sent: 40010 KB/s
|
||||||
|
#10
|
||||||
|
DC-5 Received: 6134 KB/s Sent: 7999 KB/s BufferSize: 244963
|
||||||
|
DC-3 Received: 8032 KB/s Sent: 7999 KB/s BufferSize: 326286
|
||||||
|
DC-4 Received: 5897 KB/s Sent: 7999 KB/s BufferSize: 326286
|
||||||
|
DC-2 Received: 5657 KB/s Sent: 7999 KB/s BufferSize: 326286
|
||||||
|
DC-1 Received: 5581 KB/s Sent: 7999 KB/s BufferSize: 326286
|
||||||
|
TOTL Received: 31301 KB/s Sent: 39995 KB/s
|
||||||
|
Stats# Received Total: 343 MB Sent Total: 372 MB RTT: 16 ms
|
||||||
|
|
||||||
|
#11
|
||||||
|
DC-5 Received: 6117 KB/s Sent: 7998 KB/s BufferSize: 570756
|
||||||
|
DC-3 Received: 6594 KB/s Sent: 7998 KB/s BufferSize: 570756
|
||||||
|
DC-4 Received: 6354 KB/s Sent: 7998 KB/s BufferSize: 570756
|
||||||
|
DC-2 Received: 6116 KB/s Sent: 7998 KB/s BufferSize: 570756
|
||||||
|
DC-1 Received: 5959 KB/s Sent: 7998 KB/s BufferSize: 570756
|
||||||
|
TOTL Received: 31140 KB/s Sent: 39990 KB/s
|
||||||
|
#12
|
||||||
|
DC-5 Received: 6840 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 7468 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 7472 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 7473 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 7236 KB/s Sent: 7999 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 36489 KB/s Sent: 39995 KB/s
|
||||||
|
#13
|
||||||
|
DC-5 Received: 8105 KB/s Sent: 7989 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 8020 KB/s Sent: 7989 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 8097 KB/s Sent: 7989 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 8106 KB/s Sent: 7989 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 8018 KB/s Sent: 7989 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 40346 KB/s Sent: 39945 KB/s
|
||||||
|
#14
|
||||||
|
DC-5 Received: 8042 KB/s Sent: 8007 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 8029 KB/s Sent: 8007 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 8038 KB/s Sent: 8007 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 8035 KB/s Sent: 8007 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 8036 KB/s Sent: 8007 KB/s BufferSize: 0
|
||||||
|
TOTL Received: 40180 KB/s Sent: 40035 KB/s
|
||||||
|
#15
|
||||||
|
DC-5 Received: 7981 KB/s Sent: 8001 KB/s BufferSize: 0
|
||||||
|
DC-3 Received: 7987 KB/s Sent: 8001 KB/s BufferSize: 0
|
||||||
|
DC-4 Received: 7980 KB/s Sent: 8001 KB/s BufferSize: 0
|
||||||
|
DC-2 Received: 7974 KB/s Sent: 8001 KB/s BufferSize: 0
|
||||||
|
DC-1 Received: 7972 KB/s Sent: 8001 KB/s BufferSize: 82497
|
||||||
|
TOTL Received: 39894 KB/s Sent: 40005 KB/s
|
||||||
|
Stats# Received Total: 538 MB Sent Total: 581 MB RTT: 3 ms
|
||||||
```
|
```
|
@ -31,6 +31,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
@ -61,7 +62,8 @@ string randomId(size_t length);
|
|||||||
// Benchmark
|
// Benchmark
|
||||||
const size_t messageSize = 65535;
|
const size_t messageSize = 65535;
|
||||||
binary messageData(messageSize);
|
binary messageData(messageSize);
|
||||||
atomic<size_t> receivedSize = 0, sentSize = 0;
|
unordered_map<string, atomic<size_t>> receivedSizeMap;
|
||||||
|
unordered_map<string, atomic<size_t>> sentSizeMap;
|
||||||
bool noSend = false;
|
bool noSend = false;
|
||||||
|
|
||||||
// Benchmark - enableThroughputSet params
|
// Benchmark - enableThroughputSet params
|
||||||
@ -69,7 +71,7 @@ bool enableThroughputSet;
|
|||||||
int throughtputSetAsKB;
|
int throughtputSetAsKB;
|
||||||
int bufferSize;
|
int bufferSize;
|
||||||
const float STEP_COUNT_FOR_1_SEC = 100.0;
|
const float STEP_COUNT_FOR_1_SEC = 100.0;
|
||||||
const int stepDurationInMs = 1000 / STEP_COUNT_FOR_1_SEC;
|
const int stepDurationInMs = int(1000 / STEP_COUNT_FOR_1_SEC);
|
||||||
|
|
||||||
int main(int argc, char **argv) try {
|
int main(int argc, char **argv) try {
|
||||||
Cmdline params(argc, argv);
|
Cmdline params(argc, argv);
|
||||||
@ -188,63 +190,67 @@ int main(int argc, char **argv) try {
|
|||||||
auto pc = createPeerConnection(config, ws, id);
|
auto pc = createPeerConnection(config, ws, id);
|
||||||
|
|
||||||
// We are the offerer, so create a data channel to initiate the process
|
// We are the offerer, so create a data channel to initiate the process
|
||||||
const string label = "benchmark";
|
for (int i = 1; i <= params.dataChannelCount(); i++) {
|
||||||
cout << "Creating DataChannel with label \"" << label << "\"" << endl;
|
const string label = "DC-" + std::to_string(i);
|
||||||
auto dc = pc->createDataChannel(label);
|
cout << "Creating DataChannel with label \"" << label << "\"" << endl;
|
||||||
|
auto dc = pc->createDataChannel(label);
|
||||||
|
receivedSizeMap.emplace(label, 0);
|
||||||
|
sentSizeMap.emplace(label, 0);
|
||||||
|
|
||||||
// Set Buffer Size
|
// Set Buffer Size
|
||||||
dc->setBufferedAmountLowThreshold(bufferSize);
|
dc->setBufferedAmountLowThreshold(bufferSize);
|
||||||
|
|
||||||
dc->onOpen([id, wdc = make_weak_ptr(dc)]() {
|
dc->onOpen([id, wdc = make_weak_ptr(dc), label]() {
|
||||||
cout << "DataChannel from " << id << " open" << endl;
|
cout << "DataChannel from " << id << " open" << endl;
|
||||||
if (noSend)
|
if (noSend)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (enableThroughputSet)
|
if (enableThroughputSet)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (auto dcLocked = wdc.lock()) {
|
if (auto dcLocked = wdc.lock()) {
|
||||||
|
try {
|
||||||
|
while (dcLocked->bufferedAmount() <= bufferSize) {
|
||||||
|
dcLocked->send(messageData);
|
||||||
|
sentSizeMap.at(label) += messageData.size();
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cout << "Send failed: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc), label]() {
|
||||||
|
if (noSend)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (enableThroughputSet)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto dcLocked = wdc.lock();
|
||||||
|
if (!dcLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Continue sending
|
||||||
try {
|
try {
|
||||||
while (dcLocked->bufferedAmount() <= bufferSize) {
|
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
|
||||||
dcLocked->send(messageData);
|
dcLocked->send(messageData);
|
||||||
sentSize += messageData.size();
|
sentSizeMap.at(label) += messageData.size();
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cout << "Send failed: " << e.what() << std::endl;
|
std::cout << "Send failed: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc)]() {
|
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
|
||||||
if (noSend)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (enableThroughputSet)
|
dc->onMessage([id, wdc = make_weak_ptr(dc), label](variant<binary, string> data) {
|
||||||
return;
|
if (holds_alternative<binary>(data))
|
||||||
|
receivedSizeMap.at(label) += get<binary>(data).size();
|
||||||
|
});
|
||||||
|
|
||||||
auto dcLocked = wdc.lock();
|
dataChannelMap.emplace(label, dc);
|
||||||
if (!dcLocked)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
// Continue sending
|
|
||||||
try {
|
|
||||||
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
|
|
||||||
dcLocked->send(messageData);
|
|
||||||
sentSize += messageData.size();
|
|
||||||
}
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
std::cout << "Send failed: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
|
|
||||||
|
|
||||||
dc->onMessage([id, wdc = make_weak_ptr(dc)](variant<binary, string> data) {
|
|
||||||
if (holds_alternative<binary>(data))
|
|
||||||
receivedSize += get<binary>(data).size();
|
|
||||||
});
|
|
||||||
|
|
||||||
dataChannelMap.emplace(id, dc);
|
|
||||||
|
|
||||||
const int duration = params.durationInSec() > 0 ? params.durationInSec() : INT32_MAX;
|
const int duration = params.durationInSec() > 0 ? params.durationInSec() : INT32_MAX;
|
||||||
cout << "Benchmark will run for " << duration << " seconds" << endl;
|
cout << "Benchmark will run for " << duration << " seconds" << endl;
|
||||||
@ -271,25 +277,39 @@ int main(int argc, char **argv) try {
|
|||||||
binary tempMessageData(byteToSendThisLoop);
|
binary tempMessageData(byteToSendThisLoop);
|
||||||
fill(tempMessageData.begin(), tempMessageData.end(), std::byte(0xFF));
|
fill(tempMessageData.begin(), tempMessageData.end(), std::byte(0xFF));
|
||||||
|
|
||||||
if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) {
|
for (const auto &[label, dc] : dataChannelMap) {
|
||||||
dc->send(tempMessageData);
|
if (dc->isOpen() && dc->bufferedAmount() <= bufferSize * byteToSendOnEveryLoop) {
|
||||||
sentSize += tempMessageData.size();
|
dc->send(tempMessageData);
|
||||||
|
sentSizeMap.at(label) += tempMessageData.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printCounter >= STEP_COUNT_FOR_1_SEC) {
|
if (printCounter >= STEP_COUNT_FOR_1_SEC) {
|
||||||
unsigned long _receivedSize = receivedSize.exchange(0);
|
|
||||||
unsigned long _sentSize = sentSize.exchange(0);
|
|
||||||
const double elapsedTimeInSecs =
|
const double elapsedTimeInSecs =
|
||||||
std::chrono::duration<double>(steady_clock::now() - printTime).count();
|
std::chrono::duration<double>(steady_clock::now() - printTime).count();
|
||||||
printTime = steady_clock::now();
|
printTime = steady_clock::now();
|
||||||
|
|
||||||
cout << "#" << i / STEP_COUNT_FOR_1_SEC
|
unsigned long receiveSpeedTotal = 0;
|
||||||
<< " Received: " << static_cast<int>(_receivedSize / (elapsedTimeInSecs * 1000))
|
unsigned long sendSpeedTotal = 0;
|
||||||
<< " KB/s"
|
cout << "#" << i / STEP_COUNT_FOR_1_SEC << endl;
|
||||||
<< " Sent: " << static_cast<int>(_sentSize / (elapsedTimeInSecs * 1000))
|
for (const auto &[label, dc] : dataChannelMap) {
|
||||||
<< " KB/s"
|
unsigned long channelReceiveSpeed = static_cast<int>(
|
||||||
<< " BufferSize: " << dc->bufferedAmount() << endl;
|
receivedSizeMap[label].exchange(0) / (elapsedTimeInSecs * 1000));
|
||||||
|
unsigned long channelSendSpeed =
|
||||||
|
static_cast<int>(sentSizeMap[label].exchange(0) / (elapsedTimeInSecs * 1000));
|
||||||
|
|
||||||
|
cout << std::setw(10) << label << " Received: " << channelReceiveSpeed << " KB/s"
|
||||||
|
<< " Sent: " << channelSendSpeed << " KB/s"
|
||||||
|
<< " BufferSize: " << dc->bufferedAmount() << endl;
|
||||||
|
|
||||||
|
receiveSpeedTotal += channelReceiveSpeed;
|
||||||
|
sendSpeedTotal += channelSendSpeed;
|
||||||
|
}
|
||||||
|
cout << std::setw(10) << "TOTL"
|
||||||
|
<< " Received: " << receiveSpeedTotal << " KB/s"
|
||||||
|
<< " Sent: " << sendSpeedTotal << " KB/s" << endl;
|
||||||
|
|
||||||
printStatCounter++;
|
printStatCounter++;
|
||||||
printCounter = 0;
|
printCounter = 0;
|
||||||
}
|
}
|
||||||
@ -308,12 +328,16 @@ int main(int argc, char **argv) try {
|
|||||||
|
|
||||||
dataChannelMap.clear();
|
dataChannelMap.clear();
|
||||||
peerConnectionMap.clear();
|
peerConnectionMap.clear();
|
||||||
|
receivedSizeMap.clear();
|
||||||
|
sentSizeMap.clear();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cout << "Error: " << e.what() << std::endl;
|
std::cout << "Error: " << e.what() << std::endl;
|
||||||
dataChannelMap.clear();
|
dataChannelMap.clear();
|
||||||
peerConnectionMap.clear();
|
peerConnectionMap.clear();
|
||||||
|
receivedSizeMap.clear();
|
||||||
|
sentSizeMap.clear();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,13 +370,16 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
});
|
});
|
||||||
|
|
||||||
pc->onDataChannel([id](shared_ptr<DataChannel> dc) {
|
pc->onDataChannel([id](shared_ptr<DataChannel> dc) {
|
||||||
cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
|
const string label = dc->label();
|
||||||
<< endl;
|
cout << "DataChannel from " << id << " received with label \"" << label << "\"" << endl;
|
||||||
|
|
||||||
cout << "###########################################" << endl;
|
cout << "###########################################" << endl;
|
||||||
cout << "### Check other peer's screen for stats ###" << endl;
|
cout << "### Check other peer's screen for stats ###" << endl;
|
||||||
cout << "###########################################" << endl;
|
cout << "###########################################" << endl;
|
||||||
|
|
||||||
|
receivedSizeMap.emplace(dc->label(), 0);
|
||||||
|
sentSizeMap.emplace(dc->label(), 0);
|
||||||
|
|
||||||
// Set Buffer Size
|
// Set Buffer Size
|
||||||
dc->setBufferedAmountLowThreshold(bufferSize);
|
dc->setBufferedAmountLowThreshold(bufferSize);
|
||||||
|
|
||||||
@ -360,7 +387,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
try {
|
try {
|
||||||
while (dc->bufferedAmount() <= bufferSize) {
|
while (dc->bufferedAmount() <= bufferSize) {
|
||||||
dc->send(messageData);
|
dc->send(messageData);
|
||||||
sentSize += messageData.size();
|
sentSizeMap.at(label) += messageData.size();
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cout << "Send failed: " << e.what() << std::endl;
|
std::cout << "Send failed: " << e.what() << std::endl;
|
||||||
@ -370,7 +397,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
if (!noSend && enableThroughputSet) {
|
if (!noSend && enableThroughputSet) {
|
||||||
// Create Send Data Thread
|
// Create Send Data Thread
|
||||||
// Thread will join when data channel destroyed or closed
|
// Thread will join when data channel destroyed or closed
|
||||||
std::thread([wdc = make_weak_ptr(dc)]() {
|
std::thread([wdc = make_weak_ptr(dc), label]() {
|
||||||
steady_clock::time_point stepTime = steady_clock::now();
|
steady_clock::time_point stepTime = steady_clock::now();
|
||||||
// Byte count to send for every loop
|
// Byte count to send for every loop
|
||||||
int byteToSendOnEveryLoop = throughtputSetAsKB * stepDurationInMs;
|
int byteToSendOnEveryLoop = throughtputSetAsKB * stepDurationInMs;
|
||||||
@ -399,7 +426,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
|
|
||||||
if (dcLocked->bufferedAmount() <= bufferSize) {
|
if (dcLocked->bufferedAmount() <= bufferSize) {
|
||||||
dcLocked->send(tempMessageData);
|
dcLocked->send(tempMessageData);
|
||||||
sentSize += tempMessageData.size();
|
sentSizeMap.at(label) += tempMessageData.size();
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cout << "Send failed: " << e.what() << std::endl;
|
std::cout << "Send failed: " << e.what() << std::endl;
|
||||||
@ -409,7 +436,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
}).detach();
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc)]() {
|
dc->onBufferedAmountLow([wdc = make_weak_ptr(dc), label]() {
|
||||||
if (noSend)
|
if (noSend)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -424,7 +451,7 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
try {
|
try {
|
||||||
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
|
while (dcLocked->isOpen() && dcLocked->bufferedAmount() <= bufferSize) {
|
||||||
dcLocked->send(messageData);
|
dcLocked->send(messageData);
|
||||||
sentSize += messageData.size();
|
sentSizeMap.at(label) += messageData.size();
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cout << "Send failed: " << e.what() << std::endl;
|
std::cout << "Send failed: " << e.what() << std::endl;
|
||||||
@ -433,12 +460,12 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
|
|
||||||
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
|
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
|
||||||
|
|
||||||
dc->onMessage([id, wdc = make_weak_ptr(dc)](variant<binary, string> data) {
|
dc->onMessage([id, wdc = make_weak_ptr(dc), label](variant<binary, string> data) {
|
||||||
if (holds_alternative<binary>(data))
|
if (holds_alternative<binary>(data))
|
||||||
receivedSize += get<binary>(data).size();
|
receivedSizeMap.at(label) += get<binary>(data).size();
|
||||||
});
|
});
|
||||||
|
|
||||||
dataChannelMap.emplace(id, dc);
|
dataChannelMap.emplace(label, dc);
|
||||||
});
|
});
|
||||||
|
|
||||||
peerConnectionMap.emplace(id, pc);
|
peerConnectionMap.emplace(id, pc);
|
||||||
|
@ -51,6 +51,7 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
|
|||||||
{"enableThroughputSet", no_argument, NULL, 'p'},
|
{"enableThroughputSet", no_argument, NULL, 'p'},
|
||||||
{"throughtputSetAsKB", required_argument, NULL, 'r'},
|
{"throughtputSetAsKB", required_argument, NULL, 'r'},
|
||||||
{"bufferSize", required_argument, NULL, 'b'},
|
{"bufferSize", required_argument, NULL, 'b'},
|
||||||
|
{"dataChannelCount", required_argument, NULL, 'c'},
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{NULL, 0, NULL, 0}};
|
{NULL, 0, NULL, 0}};
|
||||||
|
|
||||||
@ -68,9 +69,10 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
|
|||||||
_p = false;
|
_p = false;
|
||||||
_r = 300;
|
_r = 300;
|
||||||
_b = 0;
|
_b = 0;
|
||||||
|
_c = 1;
|
||||||
|
|
||||||
optind = 0;
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "s:t:w:x:d:r:b:enhvop", long_options, &optind)) != -1) {
|
while ((c = getopt_long(argc, argv, "s:t:w:x:d:r:b:c:enhvop", long_options, &optind)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'n':
|
case 'n':
|
||||||
_n = true;
|
_n = true;
|
||||||
@ -147,6 +149,15 @@ Cmdline::Cmdline(int argc, char *argv[]) // ISO C++17 not allowed: throw (std::s
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
_c = atoi(optarg);
|
||||||
|
if (_c <= 0) {
|
||||||
|
std::string err;
|
||||||
|
err += "parameter range error: c must be > 0";
|
||||||
|
throw(std::range_error(err));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
_h = true;
|
_h = true;
|
||||||
this->usage(EXIT_SUCCESS);
|
this->usage(EXIT_SUCCESS);
|
||||||
@ -196,6 +207,8 @@ libdatachannel client implementing WebRTC Data Channels with WebSocket signaling
|
|||||||
Send a constant data per second (KB). See throughtputSetAsKB params.\n\
|
Send a constant data per second (KB). See throughtputSetAsKB params.\n\
|
||||||
[ -r ] [ --throughtputSetAsKB ] (type=INTEGER, range>0...INT_MAX, default=300)\n\
|
[ -r ] [ --throughtputSetAsKB ] (type=INTEGER, range>0...INT_MAX, default=300)\n\
|
||||||
Send constant data per second (KB).\n\
|
Send constant data per second (KB).\n\
|
||||||
|
[ -c ] [ --dataChannelCount ] (type=INTEGER, range>0...INT_MAX, default=1)\n\
|
||||||
|
Dat Channel count to create.\n\
|
||||||
[ -h ] [ --help ] (type=FLAG)\n\
|
[ -h ] [ --help ] (type=FLAG)\n\
|
||||||
Display this help and exit.\n";
|
Display this help and exit.\n";
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ private:
|
|||||||
bool _p;
|
bool _p;
|
||||||
int _r;
|
int _r;
|
||||||
int _b;
|
int _b;
|
||||||
|
int _c;
|
||||||
|
|
||||||
/* other stuff to keep track of */
|
/* other stuff to keep track of */
|
||||||
std::string _program_name;
|
std::string _program_name;
|
||||||
@ -69,9 +70,10 @@ public:
|
|||||||
bool h () const { return _h; }
|
bool h () const { return _h; }
|
||||||
int durationInSec () const { return _d; }
|
int durationInSec () const { return _d; }
|
||||||
bool noSend () const { return _o; }
|
bool noSend () const { return _o; }
|
||||||
int bufferSize() const { return _b;}
|
int bufferSize() const { return _b; }
|
||||||
bool enableThroughputSet () const { return _p; }
|
bool enableThroughputSet () const { return _p; }
|
||||||
int throughtputSetAsKB() const { return _r;}
|
int throughtputSetAsKB() const { return _r; }
|
||||||
|
int dataChannelCount() const { return _c; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -222,9 +222,14 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
|
cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
|
dc->onOpen([wdc = make_weak_ptr(dc)]() {
|
||||||
|
if (auto dc = wdc.lock())
|
||||||
|
dc->send("Hello from " + localId);
|
||||||
|
});
|
||||||
|
|
||||||
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
|
dc->onClosed([id]() { cout << "DataChannel from " << id << " closed" << endl; });
|
||||||
|
|
||||||
dc->onMessage([id, wdc = make_weak_ptr(dc)](variant<binary, string> data) {
|
dc->onMessage([id](variant<binary, string> data) {
|
||||||
if (holds_alternative<string>(data))
|
if (holds_alternative<string>(data))
|
||||||
cout << "Message from " << id << " received: " << get<string>(data) << endl;
|
cout << "Message from " << id << " received: " << get<string>(data) << endl;
|
||||||
else
|
else
|
||||||
@ -232,8 +237,6 @@ shared_ptr<PeerConnection> createPeerConnection(const Configuration &config,
|
|||||||
<< " received, size=" << get<binary>(data).size() << endl;
|
<< " received, size=" << get<binary>(data).size() << endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
dc->send("Hello from " + localId);
|
|
||||||
|
|
||||||
dataChannelMap.emplace(id, dc);
|
dataChannelMap.emplace(id, dc);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -251,4 +254,3 @@ string randomId(size_t length) {
|
|||||||
generate(id.begin(), id.end(), [&]() { return characters.at(dist(rng)); });
|
generate(id.begin(), id.end(), [&]() { return characters.at(dist(rng)); });
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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",
|
"version": "0.1.0",
|
||||||
"license": "GPL-2.0",
|
"license": "GPL-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"websocket": "^1.0.33"
|
"websocket": "^1.0.34"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bufferutil": {
|
"node_modules/bufferutil": {
|
||||||
@ -128,9 +128,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/websocket": {
|
"node_modules/websocket": {
|
||||||
"version": "1.0.33",
|
"version": "1.0.34",
|
||||||
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
|
||||||
"integrity": "sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==",
|
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bufferutil": "^4.0.1",
|
"bufferutil": "^4.0.1",
|
||||||
"debug": "^2.2.0",
|
"debug": "^2.2.0",
|
||||||
@ -264,9 +264,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"websocket": {
|
"websocket": {
|
||||||
"version": "1.0.33",
|
"version": "1.0.34",
|
||||||
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
|
||||||
"integrity": "sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==",
|
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bufferutil": "^4.0.1",
|
"bufferutil": "^4.0.1",
|
||||||
"debug": "^2.2.0",
|
"debug": "^2.2.0",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "libdatachannel-signaling-server",
|
"name": "libdatachannel-signaling-server",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Signaling server example for libdatachannel",
|
"description": "Signaling server example for libdatachannel",
|
||||||
"main": "server.js",
|
"main": "signaling-server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node signaling-server.js",
|
"start": "node signaling-server.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
@ -18,6 +18,6 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/paullouisageneau/libdatachannel#readme",
|
"homepage": "https://github.com/paullouisageneau/libdatachannel#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"websocket": "^1.0.33"
|
"websocket": "^1.0.34"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const websocket = require('websocket');
|
const websocket = require('websocket');
|
||||||
|
|
||||||
|
@ -17,9 +17,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "h264fileparser.hpp"
|
#include "h264fileparser.hpp"
|
||||||
#include <fstream>
|
|
||||||
#include "rtc/rtc.hpp"
|
#include "rtc/rtc.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
H264FileParser::H264FileParser(string directory, uint32_t fps, bool loop): FileParser(directory, ".h264", fps, loop) { }
|
H264FileParser::H264FileParser(string directory, uint32_t fps, bool loop): FileParser(directory, ".h264", fps, loop) { }
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#if _WIN32
|
#ifdef _WIN32
|
||||||
// taken from https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows
|
// taken from https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows
|
||||||
|
#include <windows.h>
|
||||||
#include <Windows.h>
|
#include <winsock2.h> // for struct timeval
|
||||||
|
|
||||||
struct timezone {
|
struct timezone {
|
||||||
int tz_minuteswest;
|
int tz_minuteswest;
|
||||||
@ -55,6 +55,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -218,11 +218,11 @@ shared_ptr<ClientTrackData> addVideo(const shared_ptr<PeerConnection> pc, const
|
|||||||
video.addSSRC(ssrc, cname, msid, cname);
|
video.addSSRC(ssrc, cname, msid, cname);
|
||||||
auto track = pc->addTrack(video);
|
auto track = pc->addTrack(video);
|
||||||
// create RTP configuration
|
// create RTP configuration
|
||||||
auto rtpConfig = shared_ptr<RtpPacketizationConfig>(new RtpPacketizationConfig(ssrc, cname, payloadType, H264RtpPacketizer::defaultClockRate));
|
auto rtpConfig = make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, H264RtpPacketizer::defaultClockRate);
|
||||||
// create packetizer
|
// create packetizer
|
||||||
auto packetizer = shared_ptr<H264RtpPacketizer>(new H264RtpPacketizer(H264RtpPacketizer::Separator::Length, rtpConfig));
|
auto packetizer = make_shared<H264RtpPacketizer>(H264RtpPacketizer::Separator::Length, rtpConfig);
|
||||||
// create H264 handler
|
// create H264 handler
|
||||||
shared_ptr<H264PacketizationHandler> h264Handler(new H264PacketizationHandler(packetizer));
|
auto h264Handler = make_shared<H264PacketizationHandler>(packetizer);
|
||||||
// add RTCP SR handler
|
// add RTCP SR handler
|
||||||
auto srReporter = make_shared<RtcpSrReporter>(rtpConfig);
|
auto srReporter = make_shared<RtcpSrReporter>(rtpConfig);
|
||||||
h264Handler->addToChain(srReporter);
|
h264Handler->addToChain(srReporter);
|
||||||
@ -242,7 +242,7 @@ shared_ptr<ClientTrackData> addAudio(const shared_ptr<PeerConnection> pc, const
|
|||||||
audio.addSSRC(ssrc, cname, msid, cname);
|
audio.addSSRC(ssrc, cname, msid, cname);
|
||||||
auto track = pc->addTrack(audio);
|
auto track = pc->addTrack(audio);
|
||||||
// create RTP configuration
|
// create RTP configuration
|
||||||
auto rtpConfig = shared_ptr<RtpPacketizationConfig>(new RtpPacketizationConfig(ssrc, cname, payloadType, OpusRtpPacketizer::defaultClockRate));
|
auto rtpConfig = make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, OpusRtpPacketizer::defaultClockRate);
|
||||||
// create packetizer
|
// create packetizer
|
||||||
auto packetizer = make_shared<OpusRtpPacketizer>(rtpConfig);
|
auto packetizer = make_shared<OpusRtpPacketizer>(rtpConfig);
|
||||||
// create opus handler
|
// create opus handler
|
||||||
@ -265,7 +265,7 @@ shared_ptr<Client> createPeerConnection(const Configuration &config,
|
|||||||
weak_ptr<WebSocket> wws,
|
weak_ptr<WebSocket> wws,
|
||||||
string id) {
|
string id) {
|
||||||
auto pc = make_shared<PeerConnection>(config);
|
auto pc = make_shared<PeerConnection>(config);
|
||||||
shared_ptr<Client> client(new Client(pc));
|
auto client = make_shared<Client>(pc);
|
||||||
|
|
||||||
pc->onStateChange([id](PeerConnection::State state) {
|
pc->onStateChange([id](PeerConnection::State state) {
|
||||||
cout << "State: " << state << endl;
|
cout << "State: " << state << endl;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include "stream.hpp"
|
#include "stream.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
#if _WIN32
|
#ifdef _WIN32
|
||||||
// taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw
|
// taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@ -35,6 +35,8 @@ void usleep(__int64 usec)
|
|||||||
WaitForSingleObject(timer, INFINITE);
|
WaitForSingleObject(timer, INFINITE);
|
||||||
CloseHandle(timer);
|
CloseHandle(timer);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void StreamSource::stop() {
|
void StreamSource::stop() {
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
|
|
||||||
#include "rtc.h" // for C API defines
|
#include "rtc.h" // for C API defines
|
||||||
|
|
||||||
#include "log.hpp"
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@ -70,6 +69,7 @@ using binary = std::vector<byte>;
|
|||||||
using binary_ptr = std::shared_ptr<binary>;
|
using binary_ptr = std::shared_ptr<binary>;
|
||||||
|
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
|
using std::ptrdiff_t;
|
||||||
using std::uint16_t;
|
using std::uint16_t;
|
||||||
using std::uint32_t;
|
using std::uint32_t;
|
||||||
using std::uint64_t;
|
using std::uint64_t;
|
||||||
|
@ -42,7 +42,14 @@ class RTC_CPP_EXPORT Description {
|
|||||||
public:
|
public:
|
||||||
enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
|
enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
|
||||||
enum class Role { ActPass, Passive, Active };
|
enum class Role { ActPass, Passive, Active };
|
||||||
enum class Direction { SendOnly, RecvOnly, SendRecv, Inactive, Unknown };
|
|
||||||
|
enum class Direction {
|
||||||
|
SendOnly = RTC_DIRECTION_SENDONLY,
|
||||||
|
RecvOnly = RTC_DIRECTION_RECVONLY,
|
||||||
|
SendRecv = RTC_DIRECTION_SENDRECV,
|
||||||
|
Inactive = RTC_DIRECTION_INACTIVE,
|
||||||
|
Unknown = RTC_DIRECTION_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass);
|
Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass);
|
||||||
Description(const string &sdp, string typeString);
|
Description(const string &sdp, string typeString);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2019 Paul-Louis Ageneau
|
* Copyright (c) 2020-2021 Paul-Louis Ageneau
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -16,27 +16,13 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_LOG_H
|
#ifndef RTC_GLOBAL_H
|
||||||
#define RTC_LOG_H
|
#define RTC_GLOBAL_H
|
||||||
|
|
||||||
// Disable warnings before including plog
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wall"
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma warning(push, 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "plog/Log.h"
|
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
enum class LogLevel { // Don't change, it must match plog severity
|
enum class LogLevel { // Don't change, it must match plog severity
|
||||||
@ -49,8 +35,29 @@ enum class LogLevel { // Don't change, it must match plog severity
|
|||||||
Verbose = 6
|
Verbose = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
RTC_CPP_EXPORT void InitLogger(LogLevel level);
|
typedef std::function<void(LogLevel level, string message)> LogCallback;
|
||||||
|
|
||||||
|
RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr);
|
||||||
|
#ifdef PLOG
|
||||||
RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
|
RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RTC_EXPORT void Preload();
|
||||||
|
RTC_EXPORT void Cleanup();
|
||||||
|
|
||||||
|
struct SctpSettings {
|
||||||
|
// For the following settings, not set means optimized default
|
||||||
|
optional<size_t> recvBufferSize; // in bytes
|
||||||
|
optional<size_t> sendBufferSize; // in bytes
|
||||||
|
optional<size_t> maxChunksOnQueue; // in chunks
|
||||||
|
optional<size_t> initialCongestionWindow; // in MTUs
|
||||||
|
optional<size_t> maxBurst; // in MTUs
|
||||||
|
optional<unsigned int> congestionControlModule; // 0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC
|
||||||
|
optional<std::chrono::milliseconds> delayedSackTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
RTC_EXPORT void SetSctpSettings(SctpSettings s);
|
||||||
|
|
||||||
} // namespace rtc
|
} // namespace rtc
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel client example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H264_PACKETIZATION_HANDLER_H
|
#ifndef RTC_H264_PACKETIZATION_HANDLER_H
|
||||||
#define H264_PACKETIZATION_HANDLER_H
|
#define RTC_H264_PACKETIZATION_HANDLER_H
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
@ -28,7 +28,7 @@
|
|||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
/// Handler for H264 packetization
|
/// Handler for H264 packetization
|
||||||
class RTC_CPP_EXPORT H264PacketizationHandler : public MediaChainableHandler {
|
class RTC_CPP_EXPORT H264PacketizationHandler final : public MediaChainableHandler {
|
||||||
public:
|
public:
|
||||||
/// Construct handler for H264 packetization.
|
/// Construct handler for H264 packetization.
|
||||||
/// @param packetizer RTP packetizer for h264
|
/// @param packetizer RTP packetizer for h264
|
||||||
@ -39,4 +39,4 @@ public:
|
|||||||
|
|
||||||
#endif /* RTC_ENABLE_MEDIA */
|
#endif /* RTC_ENABLE_MEDIA */
|
||||||
|
|
||||||
#endif /* H264_PACKETIZATION_HANDLER_H */
|
#endif /* RTC_H264_PACKETIZATION_HANDLER_H */
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef H264_RTP_PACKETIZER_H
|
#ifndef RTC_H264_RTP_PACKETIZER_H
|
||||||
#define H264_RTP_PACKETIZER_H
|
#define RTC_H264_RTP_PACKETIZER_H
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
@ -28,13 +28,13 @@
|
|||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
/// RTP packetization of h264 payload
|
/// RTP packetization of h264 payload
|
||||||
class RTC_CPP_EXPORT H264RtpPacketizer : public RtpPacketizer, public MediaHandlerRootElement {
|
class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement {
|
||||||
shared_ptr<NalUnits> splitMessage(binary_ptr message);
|
shared_ptr<NalUnits> splitMessage(binary_ptr message);
|
||||||
const uint16_t maximumFragmentSize;
|
const uint16_t maximumFragmentSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Default clock rate for H264 in RTP
|
/// Default clock rate for H264 in RTP
|
||||||
static const auto defaultClockRate = 90 * 1000;
|
inline static const uint32_t defaultClockRate = 90 * 1000;
|
||||||
|
|
||||||
/// Nalunit separator
|
/// Nalunit separator
|
||||||
enum class Separator {
|
enum class Separator {
|
||||||
@ -64,4 +64,4 @@ private:
|
|||||||
|
|
||||||
#endif /* RTC_ENABLE_MEDIA */
|
#endif /* RTC_ENABLE_MEDIA */
|
||||||
|
|
||||||
#endif /* H264_RTP_PACKETIZER_H */
|
#endif /* RTC_H264_RTP_PACKETIZER_H */
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_MEDIA_CHAINABLE_HANDLER_H
|
#ifndef RTC_MEDIA_CHAINABLE_HANDLER_H
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_MEDIA_HANDLER_ELEMENT_H
|
#ifndef RTC_MEDIA_HANDLER_ELEMENT_H
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H
|
#ifndef RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
|
||||||
#define RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H
|
#define RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
@ -42,4 +43,4 @@ public:
|
|||||||
|
|
||||||
#endif // RTC_ENABLE_MEDIA
|
#endif // RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#endif // RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H
|
#endif // RTC_MEDIA_HANDLER_ROOT_ELEMENT_H
|
||||||
|
@ -1,34 +1,38 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NAL_UNIT_H
|
#ifndef RTC_NAL_UNIT_H
|
||||||
#define NAL_UNIT_H
|
#define RTC_NAL_UNIT_H
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
/// Nalu header
|
/// Nalu header
|
||||||
struct RTC_CPP_EXPORT NalUnitHeader {
|
struct RTC_CPP_EXPORT NalUnitHeader {
|
||||||
|
uint8_t _first = 0;
|
||||||
|
|
||||||
bool forbiddenBit() { return _first >> 7; }
|
bool forbiddenBit() { return _first >> 7; }
|
||||||
uint8_t nri() { return _first >> 5 & 0x03; }
|
uint8_t nri() { return _first >> 5 & 0x03; }
|
||||||
uint8_t unitType() { return _first & 0x1F; }
|
uint8_t unitType() { return _first & 0x1F; }
|
||||||
@ -36,13 +40,12 @@ struct RTC_CPP_EXPORT NalUnitHeader {
|
|||||||
void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); }
|
void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); }
|
||||||
void setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); }
|
void setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); }
|
||||||
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
|
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t _first = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Nalu fragment header
|
/// Nalu fragment header
|
||||||
struct RTC_CPP_EXPORT NalUnitFragmentHeader {
|
struct RTC_CPP_EXPORT NalUnitFragmentHeader {
|
||||||
|
uint8_t _first = 0;
|
||||||
|
|
||||||
bool isStart() { return _first >> 7; }
|
bool isStart() { return _first >> 7; }
|
||||||
bool reservedBit6() { return (_first >> 6) & 0x01; }
|
bool reservedBit6() { return (_first >> 6) & 0x01; }
|
||||||
bool isEnd() { return (_first >> 5) & 0x01; }
|
bool isEnd() { return (_first >> 5) & 0x01; }
|
||||||
@ -52,9 +55,6 @@ struct RTC_CPP_EXPORT NalUnitFragmentHeader {
|
|||||||
void setEnd(bool isSet) { _first = (_first & 0xDF) | (isSet << 6); }
|
void setEnd(bool isSet) { _first = (_first & 0xDF) | (isSet << 6); }
|
||||||
void setReservedBit6(bool isSet) { _first = (_first & 0xBF) | (isSet << 5); }
|
void setReservedBit6(bool isSet) { _first = (_first & 0xBF) | (isSet << 5); }
|
||||||
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
|
void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); }
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t _first = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
@ -152,4 +152,4 @@ public:
|
|||||||
|
|
||||||
#endif /* RTC_ENABLE_MEDIA */
|
#endif /* RTC_ENABLE_MEDIA */
|
||||||
|
|
||||||
#endif /* NAL_UNIT_H */
|
#endif /* RTC_NAL_UNIT_H */
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel client example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_OPUS_PACKETIZATION_HANDLER_H
|
#ifndef RTC_OPUS_PACKETIZATION_HANDLER_H
|
||||||
@ -27,7 +27,7 @@
|
|||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
/// Handler for opus packetization
|
/// Handler for opus packetization
|
||||||
class RTC_CPP_EXPORT OpusPacketizationHandler : public MediaChainableHandler {
|
class RTC_CPP_EXPORT OpusPacketizationHandler final : public MediaChainableHandler {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Construct handler for opus packetization.
|
/// Construct handler for opus packetization.
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_OPUS_RTP_PACKETIZER_H
|
#ifndef RTC_OPUS_RTP_PACKETIZER_H
|
||||||
@ -27,10 +27,10 @@
|
|||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
/// RTP packetizer for opus
|
/// RTP packetizer for opus
|
||||||
class RTC_CPP_EXPORT OpusRtpPacketizer : public RtpPacketizer, public MediaHandlerRootElement {
|
class RTC_CPP_EXPORT OpusRtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement {
|
||||||
public:
|
public:
|
||||||
/// default clock rate used in opus RTP communication
|
/// default clock rate used in opus RTP communication
|
||||||
static const uint32_t defaultClockRate = 48 * 1000;
|
inline static const uint32_t defaultClockRate = 48 * 1000;
|
||||||
|
|
||||||
/// Constructs opus packetizer with given RTP configuration.
|
/// Constructs opus packetizer with given RTP configuration.
|
||||||
/// @note RTP configuration is used in packetization process which may change some configuration
|
/// @note RTP configuration is used in packetization process which may change some configuration
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "datachannel.hpp"
|
#include "datachannel.hpp"
|
||||||
#include "description.hpp"
|
#include "description.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "init.hpp"
|
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
#include "reliability.hpp"
|
#include "reliability.hpp"
|
||||||
#include "track.hpp"
|
#include "track.hpp"
|
||||||
@ -82,8 +81,6 @@ public:
|
|||||||
State state() const;
|
State state() const;
|
||||||
GatheringState gatheringState() const;
|
GatheringState gatheringState() const;
|
||||||
SignalingState signalingState() const;
|
SignalingState signalingState() const;
|
||||||
bool hasLocalDescription() const;
|
|
||||||
bool hasRemoteDescription() const;
|
|
||||||
bool hasMedia() const;
|
bool hasMedia() const;
|
||||||
optional<Description> localDescription() const;
|
optional<Description> localDescription() const;
|
||||||
optional<Description> remoteDescription() const;
|
optional<Description> remoteDescription() const;
|
||||||
|
@ -46,7 +46,8 @@ extern "C" {
|
|||||||
#define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU
|
#define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
#define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE ((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6
|
#define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE \
|
||||||
|
((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6
|
||||||
#define RTC_DEFAULT_MAXIMUM_PACKET_COUNT_FOR_NACK_CACHE ((unsigned)512)
|
#define RTC_DEFAULT_MAXIMUM_PACKET_COUNT_FOR_NACK_CACHE ((unsigned)512)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -94,61 +95,30 @@ typedef enum {
|
|||||||
RTC_CERTIFICATE_RSA = 2,
|
RTC_CERTIFICATE_RSA = 2,
|
||||||
} rtcCertificateType;
|
} rtcCertificateType;
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// video
|
// video
|
||||||
RTC_CODEC_H264 = 0,
|
RTC_CODEC_H264 = 0,
|
||||||
RTC_CODEC_VP8 = 1,
|
RTC_CODEC_VP8 = 1,
|
||||||
RTC_CODEC_VP9 = 2,
|
RTC_CODEC_VP9 = 2,
|
||||||
|
|
||||||
// audio
|
// audio
|
||||||
RTC_CODEC_OPUS = 128
|
RTC_CODEC_OPUS = 128
|
||||||
} rtcCodec;
|
} rtcCodec;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RTC_DIRECTION_UNKNOWN = 0,
|
RTC_DIRECTION_UNKNOWN = 0,
|
||||||
RTC_DIRECTION_SENDONLY = 1,
|
RTC_DIRECTION_SENDONLY = 1,
|
||||||
RTC_DIRECTION_RECVONLY = 2,
|
RTC_DIRECTION_RECVONLY = 2,
|
||||||
RTC_DIRECTION_SENDRECV = 3,
|
RTC_DIRECTION_SENDRECV = 3,
|
||||||
RTC_DIRECTION_INACTIVE = 4
|
RTC_DIRECTION_INACTIVE = 4
|
||||||
} rtcDirection;
|
} rtcDirection;
|
||||||
|
|
||||||
#endif // RTC_ENABLE_MEDIA
|
|
||||||
|
|
||||||
#define RTC_ERR_SUCCESS 0
|
#define RTC_ERR_SUCCESS 0
|
||||||
#define RTC_ERR_INVALID -1 // invalid argument
|
#define RTC_ERR_INVALID -1 // invalid argument
|
||||||
#define RTC_ERR_FAILURE -2 // runtime error
|
#define RTC_ERR_FAILURE -2 // runtime error
|
||||||
#define RTC_ERR_NOT_AVAIL -3 // element not available
|
#define RTC_ERR_NOT_AVAIL -3 // element not available
|
||||||
#define RTC_ERR_TOO_SMALL -4 // buffer too small
|
#define RTC_ERR_TOO_SMALL -4 // buffer too small
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char **iceServers;
|
|
||||||
int iceServersCount;
|
|
||||||
rtcCertificateType certificateType;
|
|
||||||
bool enableIceTcp;
|
|
||||||
bool disableAutoNegotiation;
|
|
||||||
uint16_t portRangeBegin;
|
|
||||||
uint16_t portRangeEnd;
|
|
||||||
int mtu; // <= 0 means automatic
|
|
||||||
int maxMessageSize; // <= 0 means default
|
|
||||||
} rtcConfiguration;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool unordered;
|
|
||||||
bool unreliable;
|
|
||||||
int maxPacketLifeTime; // ignored if reliable
|
|
||||||
int maxRetransmits; // ignored if reliable
|
|
||||||
} rtcReliability;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
rtcReliability reliability;
|
|
||||||
const char *protocol; // empty string if NULL
|
|
||||||
bool negotiated;
|
|
||||||
bool manualStream;
|
|
||||||
uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
|
|
||||||
} rtcDataChannelInit;
|
|
||||||
|
|
||||||
typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
|
typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
|
||||||
typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
|
typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
|
||||||
void *ptr);
|
void *ptr);
|
||||||
@ -167,14 +137,28 @@ typedef void(RTC_API *rtcBufferedAmountLowCallbackFunc)(int id, void *ptr);
|
|||||||
typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
|
typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
|
|
||||||
// NULL cb on the first call will log to stdout
|
// NULL cb on the first call will log to stdout
|
||||||
RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
|
RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
|
||||||
|
|
||||||
// User pointer
|
// User pointer
|
||||||
RTC_EXPORT void rtcSetUserPointer(int id, void *ptr);
|
RTC_EXPORT void rtcSetUserPointer(int id, void *ptr);
|
||||||
RTC_EXPORT void * rtcGetUserPointer(int i);
|
RTC_EXPORT void *rtcGetUserPointer(int i);
|
||||||
|
|
||||||
// PeerConnection
|
// PeerConnection
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char **iceServers;
|
||||||
|
int iceServersCount;
|
||||||
|
rtcCertificateType certificateType;
|
||||||
|
bool enableIceTcp;
|
||||||
|
bool disableAutoNegotiation;
|
||||||
|
uint16_t portRangeBegin;
|
||||||
|
uint16_t portRangeEnd;
|
||||||
|
int mtu; // <= 0 means automatic
|
||||||
|
int maxMessageSize; // <= 0 means default
|
||||||
|
} rtcConfiguration;
|
||||||
|
|
||||||
RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
|
RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
|
||||||
RTC_EXPORT int rtcDeletePeerConnection(int pc);
|
RTC_EXPORT int rtcDeletePeerConnection(int pc);
|
||||||
|
|
||||||
@ -201,6 +185,22 @@ RTC_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, c
|
|||||||
int remoteSize);
|
int remoteSize);
|
||||||
|
|
||||||
// DataChannel
|
// DataChannel
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool unordered;
|
||||||
|
bool unreliable;
|
||||||
|
int maxPacketLifeTime; // ignored if reliable
|
||||||
|
int maxRetransmits; // ignored if reliable
|
||||||
|
} rtcReliability;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rtcReliability reliability;
|
||||||
|
const char *protocol; // empty string if NULL
|
||||||
|
bool negotiated;
|
||||||
|
bool manualStream;
|
||||||
|
uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
|
||||||
|
} rtcDataChannelInit;
|
||||||
|
|
||||||
RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
|
RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
|
||||||
RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
|
RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
|
||||||
RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
|
RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
|
||||||
@ -213,108 +213,96 @@ RTC_EXPORT int rtcGetDataChannelProtocol(int dc, char *buffer, int size);
|
|||||||
RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability);
|
RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability);
|
||||||
|
|
||||||
// Track
|
// Track
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rtcDirection direction;
|
||||||
|
rtcCodec codec;
|
||||||
|
int payloadType;
|
||||||
|
uint32_t ssrc;
|
||||||
|
const char *mid;
|
||||||
|
const char *name; // optional
|
||||||
|
const char *msid; // optional
|
||||||
|
const char *trackId; // optional, track ID used in MSID
|
||||||
|
} rtcTrackInit;
|
||||||
|
|
||||||
RTC_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb);
|
RTC_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb);
|
||||||
RTC_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id
|
RTC_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id
|
||||||
|
RTC_EXPORT int rtcAddTrackEx(int pc, const rtcTrackInit *init); // returns tr id
|
||||||
RTC_EXPORT int rtcDeleteTrack(int tr);
|
RTC_EXPORT int rtcDeleteTrack(int tr);
|
||||||
|
|
||||||
RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
|
RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
|
||||||
|
|
||||||
// Media
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
/// Add track
|
// Media
|
||||||
/// @param pc Peer connection id
|
|
||||||
/// @param codec Codec
|
|
||||||
/// @param payloadType Payload type
|
|
||||||
/// @param ssrc SSRC
|
|
||||||
/// @param _mid MID
|
|
||||||
/// @param _direction Direction
|
|
||||||
/// @param _name Name (optional)
|
|
||||||
/// @param _msid MSID (optional)
|
|
||||||
/// @param _trackID Track ID used in MSID (optional)
|
|
||||||
/// @returns Track id
|
|
||||||
RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid, rtcDirection direction, const char *_name, const char *_msid, const char *_trackID);
|
|
||||||
|
|
||||||
/// Set H264PacketizationHandler for track
|
typedef struct {
|
||||||
/// @param tr Track id
|
uint32_t ssrc;
|
||||||
/// @param ssrc SSRC
|
const char *cname;
|
||||||
/// @param cname CName
|
uint8_t payloadType;
|
||||||
/// @param payloadType Payload Type
|
uint32_t clockRate;
|
||||||
/// @param clockRate Clock rate
|
uint16_t maxFragmentSize; // Maximum NALU fragment size
|
||||||
/// @param maxFragmentSize Maximum NALU fragment size
|
uint16_t sequenceNumber;
|
||||||
/// @param sequenceNumber Sequence number
|
uint32_t timestamp;
|
||||||
/// @param timestamp Timestamp
|
} rtcPacketizationHandlerInit;
|
||||||
RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char * cname, uint8_t payloadType, uint32_t clockRate, uint16_t maxFragmentSize, uint16_t sequenceNumber, uint32_t timestamp);
|
|
||||||
|
|
||||||
/// Set OpusPacketizationHandler for track
|
typedef struct {
|
||||||
/// @param tr Track id
|
double seconds; // Start time in seconds
|
||||||
/// @param ssrc SSRC
|
bool since1970; // true if seconds since 1970
|
||||||
/// @param cname CName
|
// false if seconds since 1900
|
||||||
/// @param payloadType Payload Type
|
uint32_t timestamp; // Start timestamp
|
||||||
/// @param clockRate Clock rate
|
} rtcStartTime;
|
||||||
/// @param _sequenceNumber Sequence number
|
|
||||||
/// @param _timestamp Timestamp
|
|
||||||
RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char * cname, uint8_t payloadType, uint32_t clockRate, uint16_t _sequenceNumber, uint32_t _timestamp);
|
|
||||||
|
|
||||||
/// Chain RtcpSrReporter to handler chain for given track
|
// Set H264PacketizationHandler for track
|
||||||
/// @param tr Track id
|
RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
|
||||||
int rtcChainRtcpSrReporter(int tr);
|
|
||||||
|
|
||||||
/// Chain RtcpNackResponder to handler chain for given track
|
// Set OpusPacketizationHandler for track
|
||||||
/// @param tr Track id
|
RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
|
||||||
/// @param maxStoredPacketsCount Maximum stored packet count
|
|
||||||
int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount);
|
// Chain RtcpSrReporter to handler chain for given track
|
||||||
|
RTC_EXPORT int rtcChainRtcpSrReporter(int tr);
|
||||||
|
|
||||||
|
// Chain RtcpNackResponder to handler chain for given track
|
||||||
|
RTC_EXPORT int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount);
|
||||||
|
|
||||||
/// Set start time for RTP stream
|
/// Set start time for RTP stream
|
||||||
/// @param startTime_s Start time in seconds
|
RTC_EXPORT int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime);
|
||||||
/// @param timeIntervalSince1970 Set true if `startTime_s` is time interval since 1970, false if `startTime_s` is time interval since 1900
|
|
||||||
/// @param _timestamp Start timestamp
|
|
||||||
int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970, uint32_t _timestamp);
|
|
||||||
|
|
||||||
/// Start stats recording for RTCP Sender Reporter
|
// Start stats recording for RTCP Sender Reporter
|
||||||
/// @param id Track identifier
|
RTC_EXPORT int rtcStartRtcpSenderReporterRecording(int id);
|
||||||
int rtcStartRtcpSenderReporterRecording(int id);
|
|
||||||
|
|
||||||
/// Transform seconds to timestamp using track's clock rate
|
// Transform seconds to timestamp using track's clock rate
|
||||||
/// @param id Track id
|
// Result is written to timestamp
|
||||||
/// @param seconds Seconds
|
RTC_EXPORT int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
|
||||||
/// @param timestamp Pointer to result
|
|
||||||
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t * timestamp);
|
|
||||||
|
|
||||||
/// Transform timestamp to seconds using track's clock rate
|
// Transform timestamp to seconds using track's clock rate
|
||||||
/// @param id Track id
|
// Result is written to seconds
|
||||||
/// @param timestamp Timestamp
|
RTC_EXPORT int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds);
|
||||||
/// @param seconds Pointer for result
|
|
||||||
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double * seconds);
|
|
||||||
|
|
||||||
/// Get current timestamp
|
// Get current timestamp
|
||||||
/// @param id Track id
|
// Result is written to timestamp
|
||||||
/// @param timestamp Pointer for result
|
RTC_EXPORT int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp);
|
||||||
int rtcGetCurrentTrackTimestamp(int id, uint32_t * timestamp);
|
|
||||||
|
|
||||||
/// Get start timestamp for track identified by given id
|
// Get start timestamp for track identified by given id
|
||||||
/// @param id Track id
|
// Result is written to timestamp
|
||||||
/// @param timestamp Pointer for result
|
RTC_EXPORT int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp);
|
||||||
int rtcGetTrackStartTimestamp(int id, uint32_t * timestamp);
|
|
||||||
|
|
||||||
/// Set RTP timestamp for track identified by given id
|
// Set RTP timestamp for track identified by given id
|
||||||
/// @param id Track id
|
RTC_EXPORT int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp);
|
||||||
/// @param timestamp New timestamp
|
|
||||||
int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp);
|
|
||||||
|
|
||||||
/// Get timestamp of previous RTCP SR
|
// Get timestamp of previous RTCP SR
|
||||||
/// @param id Track id
|
// Result is written to timestamp
|
||||||
/// @param timestamp Pointer for result
|
RTC_EXPORT int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp);
|
||||||
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t * timestamp);
|
|
||||||
|
|
||||||
/// Set `NeedsToReport` flag in RtcpSrReporter handler identified by given track id
|
// Set NeedsToReport flag in RtcpSrReporter handler identified by given track id
|
||||||
/// @param id Track id
|
RTC_EXPORT int rtcSetNeedsToSendRtcpSr(int id);
|
||||||
int rtcSetNeedsToSendRtcpSr(int id);
|
|
||||||
|
|
||||||
#endif // RTC_ENABLE_MEDIA
|
#endif // RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
// WebSocket
|
|
||||||
#if RTC_ENABLE_WEBSOCKET
|
#if RTC_ENABLE_WEBSOCKET
|
||||||
|
|
||||||
|
// WebSocket
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool disableTlsVerification; // if true, don't verify the TLS certificate
|
bool disableTlsVerification; // if true, don't verify the TLS certificate
|
||||||
} rtcWsConfiguration;
|
} rtcWsConfiguration;
|
||||||
@ -322,9 +310,11 @@ typedef struct {
|
|||||||
RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id
|
RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id
|
||||||
RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config);
|
RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config);
|
||||||
RTC_EXPORT int rtcDeleteWebsocket(int ws);
|
RTC_EXPORT int rtcDeleteWebsocket(int ws);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DataChannel, Track, and WebSocket common API
|
// DataChannel, Track, and WebSocket common API
|
||||||
|
|
||||||
RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb);
|
RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb);
|
||||||
RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb);
|
RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb);
|
||||||
RTC_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb);
|
RTC_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb);
|
||||||
@ -336,14 +326,31 @@ RTC_EXPORT int rtcSetBufferedAmountLowThreshold(int id, int amount);
|
|||||||
RTC_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb);
|
RTC_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb);
|
||||||
|
|
||||||
// DataChannel, Track, and WebSocket common extended API
|
// DataChannel, Track, and WebSocket common extended API
|
||||||
|
|
||||||
RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive
|
RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive
|
||||||
RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb);
|
RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb);
|
||||||
RTC_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size);
|
RTC_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size);
|
||||||
|
|
||||||
// Optional preload and cleanup
|
// Optional global preload and cleanup
|
||||||
|
|
||||||
RTC_EXPORT void rtcPreload(void);
|
RTC_EXPORT void rtcPreload(void);
|
||||||
RTC_EXPORT void rtcCleanup(void);
|
RTC_EXPORT void rtcCleanup(void);
|
||||||
|
|
||||||
|
// SCTP global settings
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int recvBufferSize; // in bytes, <= 0 means optimized default
|
||||||
|
int sendBufferSize; // in bytes, <= 0 means optimized default
|
||||||
|
int maxChunksOnQueue; // in chunks, <= 0 means optimized default
|
||||||
|
int initialCongestionWindow; // in MTUs, <= 0 means optimized default
|
||||||
|
int maxBurst; // in MTUs, 0 means optimized default, < 0 means disabled
|
||||||
|
int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC
|
||||||
|
int delayedSackTimeMs; // in msecs, <= 0 means optimized default
|
||||||
|
} rtcSctpSettings;
|
||||||
|
|
||||||
|
// Note: SCTP settings apply to newly-created PeerConnections only
|
||||||
|
RTC_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,12 +21,11 @@
|
|||||||
|
|
||||||
// C++ API
|
// C++ API
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "init.hpp" // for rtc::Cleanup()
|
#include "global.hpp"
|
||||||
#include "log.hpp"
|
|
||||||
//
|
//
|
||||||
#include "datachannel.hpp"
|
#include "datachannel.hpp"
|
||||||
#include "track.hpp"
|
|
||||||
#include "peerconnection.hpp"
|
#include "peerconnection.hpp"
|
||||||
|
#include "track.hpp"
|
||||||
|
|
||||||
#if RTC_ENABLE_WEBSOCKET
|
#if RTC_ENABLE_WEBSOCKET
|
||||||
|
|
||||||
@ -38,14 +37,13 @@
|
|||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
// Media handling
|
// Media handling
|
||||||
#include "rtcpreceivingsession.hpp"
|
|
||||||
#include "mediachainablehandler.hpp"
|
#include "mediachainablehandler.hpp"
|
||||||
#include "rtcpsrreporter.hpp"
|
|
||||||
#include "rtcpnackresponder.hpp"
|
#include "rtcpnackresponder.hpp"
|
||||||
|
#include "rtcpreceivingsession.hpp"
|
||||||
|
#include "rtcpsrreporter.hpp"
|
||||||
|
|
||||||
// Opus/h264 streaming
|
// Opus/h264 streaming
|
||||||
#include "h264packetizationhandler.hpp"
|
#include "h264packetizationhandler.hpp"
|
||||||
#include "opuspacketizationhandler.hpp"
|
#include "opuspacketizationhandler.hpp"
|
||||||
|
|
||||||
#endif // RTC_ENABLE_MEDIA
|
#endif // RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_RTCP_NACK_RESPONDER_H
|
#ifndef RTC_RTCP_NACK_RESPONDER_H
|
||||||
@ -27,11 +28,11 @@
|
|||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
class RTC_CPP_EXPORT RtcpNackResponder: public MediaHandlerElement {
|
class RTC_CPP_EXPORT RtcpNackResponder final: public MediaHandlerElement {
|
||||||
|
|
||||||
/// Packet storage
|
/// Packet storage
|
||||||
class RTC_CPP_EXPORT Storage {
|
class RTC_CPP_EXPORT Storage {
|
||||||
|
|
||||||
/// Packet storage element
|
/// Packet storage element
|
||||||
struct RTC_CPP_EXPORT Element {
|
struct RTC_CPP_EXPORT Element {
|
||||||
Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next = nullptr);
|
Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next = nullptr);
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_RTCP_SENDER_REPORTABLE_H
|
#ifndef RTC_RTCP_SENDER_REPORTABLE_H
|
||||||
@ -26,7 +27,7 @@
|
|||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
class RTC_CPP_EXPORT RtcpSrReporter: public MediaHandlerElement {
|
class RTC_CPP_EXPORT RtcpSrReporter final: public MediaHandlerElement {
|
||||||
|
|
||||||
bool needsToReport = false;
|
bool needsToReport = false;
|
||||||
|
|
||||||
|
@ -21,23 +21,9 @@
|
|||||||
#ifndef RTC_RTP_HPP
|
#ifndef RTC_RTP_HPP
|
||||||
#define RTC_RTP_HPP
|
#define RTC_RTP_HPP
|
||||||
|
|
||||||
#include "log.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef htonll
|
|
||||||
#define htonll(x) \
|
|
||||||
((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32)))
|
|
||||||
#endif
|
|
||||||
#ifndef ntohll
|
|
||||||
#define ntohll(x) htonll(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
@ -45,63 +31,40 @@ typedef uint32_t SSRC;
|
|||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct RTP {
|
struct RTC_CPP_EXPORT RTP {
|
||||||
private:
|
|
||||||
uint8_t _first;
|
uint8_t _first;
|
||||||
uint8_t _payloadType;
|
uint8_t _payloadType;
|
||||||
uint16_t _seqNumber;
|
uint16_t _seqNumber;
|
||||||
uint32_t _timestamp;
|
uint32_t _timestamp;
|
||||||
SSRC _ssrc;
|
SSRC _ssrc;
|
||||||
|
SSRC _csrc[16];
|
||||||
|
|
||||||
public:
|
[[nodiscard]] uint8_t version() const;
|
||||||
SSRC csrc[16];
|
[[nodiscard]] bool padding() const;
|
||||||
|
[[nodiscard]] bool extension() const;
|
||||||
|
[[nodiscard]] uint8_t csrcCount() const;
|
||||||
|
[[nodiscard]] uint8_t marker() const;
|
||||||
|
[[nodiscard]] uint8_t payloadType() const;
|
||||||
|
[[nodiscard]] uint16_t seqNumber() const;
|
||||||
|
[[nodiscard]] uint32_t timestamp() const;
|
||||||
|
[[nodiscard]] uint32_t ssrc() const;
|
||||||
|
|
||||||
inline uint8_t version() const { return _first >> 6; }
|
[[nodiscard]] size_t getSize() const;
|
||||||
inline bool padding() const { return (_first >> 5) & 0x01; }
|
[[nodiscard]] const char *getBody() const;
|
||||||
inline bool extension() const { return (_first >> 4) & 0x01; }
|
[[nodiscard]] char *getBody();
|
||||||
inline uint8_t csrcCount() const { return _first & 0x0F; }
|
|
||||||
inline uint8_t marker() const { return _payloadType & 0b10000000; }
|
|
||||||
inline uint8_t payloadType() const { return _payloadType & 0b01111111; }
|
|
||||||
inline uint16_t seqNumber() const { return ntohs(_seqNumber); }
|
|
||||||
inline uint32_t timestamp() const { return ntohl(_timestamp); }
|
|
||||||
inline uint32_t ssrc() const { return ntohl(_ssrc); }
|
|
||||||
|
|
||||||
inline size_t getSize() const {
|
void log() const;
|
||||||
return reinterpret_cast<const char *>(&csrc) - reinterpret_cast<const char *>(this) +
|
|
||||||
sizeof(SSRC) * csrcCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] char *getBody() {
|
void preparePacket();
|
||||||
return reinterpret_cast<char *>(&csrc) + sizeof(SSRC) * csrcCount();
|
void setSeqNumber(uint16_t newSeqNo);
|
||||||
}
|
void setPayloadType(uint8_t newPayloadType);
|
||||||
|
void setSsrc(uint32_t in_ssrc);
|
||||||
[[nodiscard]] const char *getBody() const {
|
void setMarker(bool marker);
|
||||||
return reinterpret_cast<const char *>(&csrc) + sizeof(SSRC) * csrcCount();
|
void setTimestamp(uint32_t i);
|
||||||
}
|
|
||||||
|
|
||||||
inline void preparePacket() { _first |= (1 << 7); }
|
|
||||||
|
|
||||||
inline void setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); }
|
|
||||||
inline void setPayloadType(uint8_t newPayloadType) {
|
|
||||||
_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
|
|
||||||
}
|
|
||||||
inline void setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); }
|
|
||||||
inline void setMarker(bool marker) { _payloadType = (_payloadType & 0x7F) | (marker << 7); };
|
|
||||||
|
|
||||||
void setTimestamp(uint32_t i) { _timestamp = htonl(i); }
|
|
||||||
|
|
||||||
void log() {
|
|
||||||
PLOG_VERBOSE << "RTP V: " << (int)version() << " P: " << (padding() ? "P" : " ")
|
|
||||||
<< " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount()
|
|
||||||
<< " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType()
|
|
||||||
<< " SEQNO: " << seqNumber() << " TS: " << timestamp();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_ReportBlock {
|
struct RTC_CPP_EXPORT RTCP_ReportBlock {
|
||||||
SSRC ssrc;
|
SSRC _ssrc;
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit
|
uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit
|
||||||
uint16_t _seqNoCycles;
|
uint16_t _seqNoCycles;
|
||||||
uint16_t _highestSeqNo;
|
uint16_t _highestSeqNo;
|
||||||
@ -109,136 +72,68 @@ private:
|
|||||||
uint32_t _lastReport;
|
uint32_t _lastReport;
|
||||||
uint32_t _delaySinceLastReport;
|
uint32_t _delaySinceLastReport;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] uint16_t seqNoCycles() const;
|
||||||
inline void preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost,
|
[[nodiscard]] uint16_t highestSeqNo() const;
|
||||||
[[maybe_unused]] unsigned int totalPackets, uint16_t highestSeqNo,
|
[[nodiscard]] uint32_t jitter() const;
|
||||||
uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP,
|
[[nodiscard]] uint32_t delaySinceSR() const;
|
||||||
uint64_t lastSR_DELAY) {
|
|
||||||
setSeqNo(highestSeqNo, seqNoCycles);
|
|
||||||
setJitter(jitter);
|
|
||||||
setSSRC(in_ssrc);
|
|
||||||
|
|
||||||
// Middle 32 bits of NTP Timestamp
|
[[nodiscard]] SSRC getSSRC() const;
|
||||||
// this->lastReport = lastSR_NTP >> 16u;
|
[[nodiscard]] uint32_t getNTPOfSR() const;
|
||||||
setNTPOfSR(uint64_t(lastSR_NTP));
|
[[nodiscard]] unsigned int getLossPercentage() const;
|
||||||
setDelaySinceSR(uint32_t(lastSR_DELAY));
|
[[nodiscard]] unsigned int getPacketLostCount() const;
|
||||||
|
|
||||||
// The delay, expressed in units of 1/65536 seconds
|
void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets,
|
||||||
// this->delaySinceLastReport = lastSR_DELAY;
|
uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter,
|
||||||
}
|
uint64_t lastSR_NTP, uint64_t lastSR_DELAY);
|
||||||
|
void setSSRC(SSRC in_ssrc);
|
||||||
|
void setPacketsLost(unsigned int packetsLost, unsigned int totalPackets);
|
||||||
|
void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles);
|
||||||
|
void setJitter(uint32_t jitter);
|
||||||
|
void setNTPOfSR(uint64_t ntp);
|
||||||
|
void setDelaySinceSR(uint32_t sr);
|
||||||
|
|
||||||
inline void setSSRC(SSRC in_ssrc) { this->ssrc = htonl(in_ssrc); }
|
void log() const;
|
||||||
[[nodiscard]] inline SSRC getSSRC() const { return ntohl(ssrc); }
|
|
||||||
|
|
||||||
inline void setPacketsLost([[maybe_unused]] unsigned int packetsLost,
|
|
||||||
[[maybe_unused]] unsigned int totalPackets) {
|
|
||||||
// TODO Implement loss percentages.
|
|
||||||
_fractionLostAndPacketsLost = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] inline unsigned int getLossPercentage() const {
|
|
||||||
// TODO Implement loss percentages.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
[[nodiscard]] inline unsigned int getPacketLostCount() const {
|
|
||||||
// TODO Implement total packets lost.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16_t seqNoCycles() const { return ntohs(_seqNoCycles); }
|
|
||||||
inline uint16_t highestSeqNo() const { return ntohs(_highestSeqNo); }
|
|
||||||
inline uint32_t jitter() const { return ntohl(_jitter); }
|
|
||||||
|
|
||||||
inline void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) {
|
|
||||||
_highestSeqNo = htons(highestSeqNo);
|
|
||||||
_seqNoCycles = htons(seqNoCycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setJitter(uint32_t jitter) { _jitter = htonl(jitter); }
|
|
||||||
|
|
||||||
inline void setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); }
|
|
||||||
[[nodiscard]] inline uint32_t getNTPOfSR() const { return ntohl(_lastReport) << 16u; }
|
|
||||||
|
|
||||||
inline void setDelaySinceSR(uint32_t sr) {
|
|
||||||
// The delay, expressed in units of 1/65536 seconds
|
|
||||||
_delaySinceLastReport = htonl(sr);
|
|
||||||
}
|
|
||||||
[[nodiscard]] inline uint32_t getDelaySinceSR() const { return ntohl(_delaySinceLastReport); }
|
|
||||||
|
|
||||||
inline void log() const {
|
|
||||||
PLOG_VERBOSE << "RTCP report block: "
|
|
||||||
<< "ssrc="
|
|
||||||
<< ntohl(ssrc)
|
|
||||||
// TODO: Implement these reports
|
|
||||||
// << ", fractionLost=" << fractionLost
|
|
||||||
// << ", packetsLost=" << packetsLost
|
|
||||||
<< ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles()
|
|
||||||
<< ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR()
|
|
||||||
<< ", lastSRDelay=" << getDelaySinceSR();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_HEADER {
|
struct RTC_CPP_EXPORT RTCP_HEADER {
|
||||||
private:
|
|
||||||
uint8_t _first;
|
uint8_t _first;
|
||||||
uint8_t _payloadType;
|
uint8_t _payloadType;
|
||||||
uint16_t _length;
|
uint16_t _length;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] uint8_t version() const;
|
||||||
inline uint8_t version() const { return _first >> 6; }
|
[[nodiscard]] bool padding() const;
|
||||||
inline bool padding() const { return (_first >> 5) & 0x01; }
|
[[nodiscard]] uint8_t reportCount() const;
|
||||||
inline uint8_t reportCount() const { return _first & 0x0F; }
|
[[nodiscard]] uint8_t payloadType() const;
|
||||||
inline uint8_t payloadType() const { return _payloadType; }
|
[[nodiscard]] uint16_t length() const;
|
||||||
inline uint16_t length() const { return ntohs(_length); }
|
[[nodiscard]] size_t lengthInBytes() const;
|
||||||
inline size_t lengthInBytes() const { return (1 + length()) * 4; }
|
|
||||||
|
|
||||||
inline void setPayloadType(uint8_t type) { _payloadType = type; }
|
void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length);
|
||||||
inline void setReportCount(uint8_t count) {
|
void setPayloadType(uint8_t type);
|
||||||
_first = (_first & 0b11100000u) | (count & 0b00011111u);
|
void setReportCount(uint8_t count);
|
||||||
}
|
void setLength(uint16_t length);
|
||||||
inline void setLength(uint16_t length) { _length = htons(length); }
|
|
||||||
|
|
||||||
inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) {
|
void log() const;
|
||||||
_first = 0b10000000; // version 2, no padding
|
|
||||||
setReportCount(reportCount);
|
|
||||||
setPayloadType(payloadType);
|
|
||||||
setLength(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void log() const {
|
|
||||||
PLOG_VERBOSE << "RTCP header: "
|
|
||||||
<< "version=" << unsigned(version()) << ", padding=" << padding()
|
|
||||||
<< ", reportCount=" << unsigned(reportCount())
|
|
||||||
<< ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_FB_HEADER {
|
struct RTC_CPP_EXPORT RTCP_FB_HEADER {
|
||||||
RTCP_HEADER header;
|
RTCP_HEADER header;
|
||||||
SSRC packetSender;
|
|
||||||
SSRC mediaSource;
|
|
||||||
|
|
||||||
[[nodiscard]] SSRC getPacketSenderSSRC() const { return ntohl(packetSender); }
|
SSRC _packetSender;
|
||||||
|
SSRC _mediaSource;
|
||||||
|
|
||||||
[[nodiscard]] SSRC getMediaSourceSSRC() const { return ntohl(mediaSource); }
|
[[nodiscard]] SSRC packetSenderSSRC() const;
|
||||||
|
[[nodiscard]] SSRC mediaSourceSSRC() const;
|
||||||
|
|
||||||
void setPacketSenderSSRC(SSRC ssrc) { this->packetSender = htonl(ssrc); }
|
void setPacketSenderSSRC(SSRC ssrc);
|
||||||
|
void setMediaSourceSSRC(SSRC ssrc);
|
||||||
|
|
||||||
void setMediaSourceSSRC(SSRC ssrc) { this->mediaSource = htonl(ssrc); }
|
void log() const;
|
||||||
|
|
||||||
void log() {
|
|
||||||
header.log();
|
|
||||||
PLOG_VERBOSE << "FB: "
|
|
||||||
<< " packet sender: " << getPacketSenderSSRC()
|
|
||||||
<< " media source: " << getMediaSourceSSRC();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_SR {
|
struct RTC_CPP_EXPORT RTCP_SR {
|
||||||
RTCP_HEADER header;
|
RTCP_HEADER header;
|
||||||
|
|
||||||
SSRC _senderSSRC;
|
SSRC _senderSSRC;
|
||||||
|
|
||||||
private:
|
|
||||||
uint64_t _ntpTimestamp;
|
uint64_t _ntpTimestamp;
|
||||||
uint32_t _rtpTimestamp;
|
uint32_t _rtpTimestamp;
|
||||||
uint32_t _packetCount;
|
uint32_t _packetCount;
|
||||||
@ -246,418 +141,175 @@ private:
|
|||||||
|
|
||||||
RTCP_ReportBlock _reportBlocks;
|
RTCP_ReportBlock _reportBlocks;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] static unsigned int Size(unsigned int reportCount);
|
||||||
inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) {
|
|
||||||
unsigned int length =
|
|
||||||
((sizeof(header) + 24 + reportCount * sizeof(RTCP_ReportBlock)) / 4) - 1;
|
|
||||||
header.prepareHeader(200, reportCount, uint16_t(length));
|
|
||||||
this->_senderSSRC = htonl(senderSSRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
|
[[nodiscard]] uint64_t ntpTimestamp() const;
|
||||||
[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
|
[[nodiscard]] uint32_t rtpTimestamp() const;
|
||||||
return &_reportBlocks + num;
|
[[nodiscard]] uint32_t packetCount() const;
|
||||||
}
|
[[nodiscard]] uint32_t octetCount() const;
|
||||||
|
[[nodiscard]] uint32_t senderSSRC() const;
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size(unsigned int reportCount) {
|
[[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
|
||||||
return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock);
|
[[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
|
||||||
}
|
[[nodiscard]] unsigned int size(unsigned int reportCount);
|
||||||
|
[[nodiscard]] size_t getSize() const;
|
||||||
|
|
||||||
[[nodiscard]] inline size_t getSize() const {
|
void preparePacket(SSRC senderSSRC, uint8_t reportCount);
|
||||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
void setNtpTimestamp(uint64_t ts);
|
||||||
return sizeof(uint32_t) * (1 + size_t(header.length()));
|
void setRtpTimestamp(uint32_t ts);
|
||||||
}
|
void setOctetCount(uint32_t ts);
|
||||||
|
void setPacketCount(uint32_t ts);
|
||||||
|
|
||||||
inline uint64_t ntpTimestamp() const { return ntohll(_ntpTimestamp); }
|
void log() const;
|
||||||
inline uint32_t rtpTimestamp() const { return ntohl(_rtpTimestamp); }
|
|
||||||
inline uint32_t packetCount() const { return ntohl(_packetCount); }
|
|
||||||
inline uint32_t octetCount() const { return ntohl(_octetCount); }
|
|
||||||
inline uint32_t senderSSRC() const { return ntohl(_senderSSRC); }
|
|
||||||
|
|
||||||
inline void setNtpTimestamp(uint64_t ts) { _ntpTimestamp = htonll(ts); }
|
|
||||||
inline void setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); }
|
|
||||||
inline void setOctetCount(uint32_t ts) { _octetCount = htonl(ts); }
|
|
||||||
inline void setPacketCount(uint32_t ts) { _packetCount = htonl(ts); }
|
|
||||||
|
|
||||||
inline void log() const {
|
|
||||||
header.log();
|
|
||||||
PLOG_VERBOSE << "RTCP SR: "
|
|
||||||
<< " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp()
|
|
||||||
<< ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount()
|
|
||||||
<< ", octetCount=" << octetCount();
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
|
||||||
getReportBlock(i)->log();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_SDES_ITEM {
|
struct RTC_CPP_EXPORT RTCP_SDES_ITEM {
|
||||||
public:
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t _length;
|
uint8_t _length;
|
||||||
char _text[1];
|
char _text[1];
|
||||||
|
|
||||||
public:
|
[[nodiscard]] static unsigned int Size(uint8_t textLength);
|
||||||
inline std::string text() const { return std::string(_text, _length); }
|
|
||||||
inline void setText(std::string text) {
|
|
||||||
if(text.size() > 0xFF)
|
|
||||||
throw std::invalid_argument("text is too long");
|
|
||||||
|
|
||||||
_length = uint8_t(text.size());
|
[[nodiscard]] string text() const;
|
||||||
memcpy(_text, text.data(), text.size());
|
[[nodiscard]] uint8_t length() const;
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t length() { return _length; }
|
void setText(string text);
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size(uint8_t textLength) { return textLength + 2; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_SDES_CHUNK {
|
struct RTCP_SDES_CHUNK {
|
||||||
private:
|
|
||||||
SSRC _ssrc;
|
SSRC _ssrc;
|
||||||
RTCP_SDES_ITEM _items;
|
RTCP_SDES_ITEM _items;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] static unsigned int Size(const std::vector<uint8_t> textLengths);
|
||||||
inline SSRC ssrc() const { return ntohl(_ssrc); }
|
|
||||||
inline void setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); }
|
|
||||||
|
|
||||||
/// Get item at given index
|
[[nodiscard]] SSRC ssrc() const;
|
||||||
/// @note All items with index < `num` must be valid, otherwise this function has undefined
|
|
||||||
/// behaviour (use `safelyCountChunkSize` to check if chunk is valid)
|
|
||||||
/// @param num Index of item to return
|
|
||||||
inline RTCP_SDES_ITEM *getItem(int num) {
|
|
||||||
auto base = &_items;
|
|
||||||
while (num-- > 0) {
|
|
||||||
auto itemSize = RTCP_SDES_ITEM::size(base->length());
|
|
||||||
base = reinterpret_cast<RTCP_SDES_ITEM *>(reinterpret_cast<uint8_t *>(base) + itemSize);
|
|
||||||
}
|
|
||||||
return reinterpret_cast<RTCP_SDES_ITEM *>(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
long safelyCountChunkSize(size_t maxChunkSize) {
|
void setSSRC(SSRC ssrc);
|
||||||
if (maxChunkSize < RTCP_SDES_CHUNK::size({})) {
|
|
||||||
// chunk is truncated
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
size_t size = sizeof(SSRC);
|
|
||||||
unsigned int i = 0;
|
|
||||||
// We can always access first 4 bytes of first item (in case of no items there will be 4
|
|
||||||
// null bytes)
|
|
||||||
auto item = getItem(i);
|
|
||||||
std::vector<uint8_t> textsLength{};
|
|
||||||
while (item->type != 0) {
|
|
||||||
if (size + RTCP_SDES_ITEM::size(0) > maxChunkSize) {
|
|
||||||
// item is too short
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
auto itemLength = item->length();
|
|
||||||
if (size + RTCP_SDES_ITEM::size(itemLength) >= maxChunkSize) {
|
|
||||||
// item is too large (it can't be equal to chunk size because after item there
|
|
||||||
// must be 1-4 null bytes as padding)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
textsLength.push_back(itemLength);
|
|
||||||
// safely to access next item
|
|
||||||
item = getItem(++i);
|
|
||||||
}
|
|
||||||
auto realSize = RTCP_SDES_CHUNK::size(textsLength);
|
|
||||||
if (realSize > maxChunkSize) {
|
|
||||||
// Chunk is too large
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return realSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size(const std::vector<uint8_t> textLengths) {
|
// Get item at given index
|
||||||
unsigned int itemsSize = 0;
|
// All items with index < num must be valid, otherwise this function has undefined behaviour
|
||||||
for (auto length : textLengths) {
|
// (use safelyCountChunkSize() to check if chunk is valid).
|
||||||
itemsSize += RTCP_SDES_ITEM::size(length);
|
[[nodiscard]] const RTCP_SDES_ITEM *getItem(int num) const;
|
||||||
}
|
[[nodiscard]] RTCP_SDES_ITEM *getItem(int num);
|
||||||
auto nullTerminatedItemsSize = itemsSize + 1;
|
|
||||||
auto words = uint8_t(std::ceil(double(nullTerminatedItemsSize) / 4)) + 1;
|
|
||||||
return words * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get size of chunk
|
// Get size of chunk
|
||||||
/// @note All items must be valid, otherwise this function has undefined behaviour (use
|
// All items must be valid, otherwise this function has undefined behaviour (use
|
||||||
/// `safelyCountChunkSize` to check if chunk is valid)
|
// safelyCountChunkSize() to check if chunk is valid)
|
||||||
[[nodiscard]] unsigned int getSize() {
|
[[nodiscard]] unsigned int getSize() const;
|
||||||
std::vector<uint8_t> textLengths{};
|
|
||||||
unsigned int i = 0;
|
long safelyCountChunkSize(size_t maxChunkSize) const;
|
||||||
auto item = getItem(i);
|
|
||||||
while (item->type != 0) {
|
|
||||||
textLengths.push_back(item->length());
|
|
||||||
item = getItem(++i);
|
|
||||||
}
|
|
||||||
return size(textLengths);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_SDES {
|
struct RTC_CPP_EXPORT RTCP_SDES {
|
||||||
RTCP_HEADER header;
|
RTCP_HEADER header;
|
||||||
|
|
||||||
private:
|
|
||||||
RTCP_SDES_CHUNK _chunks;
|
RTCP_SDES_CHUNK _chunks;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] static unsigned int Size(const std::vector<std::vector<uint8_t>> lengths);
|
||||||
inline void preparePacket(uint8_t chunkCount) {
|
|
||||||
unsigned int chunkSize = 0;
|
|
||||||
for (uint8_t i = 0; i < chunkCount; i++) {
|
|
||||||
auto chunk = getChunk(i);
|
|
||||||
chunkSize += chunk->getSize();
|
|
||||||
}
|
|
||||||
uint16_t length = uint16_t((sizeof(header) + chunkSize) / 4 - 1);
|
|
||||||
header.prepareHeader(202, chunkCount, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() {
|
bool isValid() const;
|
||||||
auto chunksSize = header.lengthInBytes() - sizeof(header);
|
|
||||||
if (chunksSize == 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// there is at least one chunk
|
|
||||||
unsigned int i = 0;
|
|
||||||
unsigned int size = 0;
|
|
||||||
while (size < chunksSize) {
|
|
||||||
if (chunksSize < size + RTCP_SDES_CHUNK::size({})) {
|
|
||||||
// chunk is truncated
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto chunk = getChunk(i++);
|
|
||||||
auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size);
|
|
||||||
if (chunkSize < 0) {
|
|
||||||
// chunk is invalid
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size += chunkSize;
|
|
||||||
}
|
|
||||||
return size == chunksSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns number of chunks in this packet
|
// Returns number of chunks in this packet
|
||||||
/// @note Returns 0 if packet is invalid
|
// Returns 0 if packet is invalid
|
||||||
inline unsigned int chunksCount() {
|
unsigned int chunksCount() const;
|
||||||
if (!isValid()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header);
|
|
||||||
unsigned int size = 0;
|
|
||||||
unsigned int i = 0;
|
|
||||||
while (size < chunksSize) {
|
|
||||||
size += getChunk(i++)->getSize();
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get chunk at given index
|
// Get chunk at given index
|
||||||
/// @note All chunks (and their items) with index < `num` must be valid, otherwise this function
|
// All chunks (and their items) with index < `num` must be valid, otherwise this function has
|
||||||
/// has undefined behaviour (use `isValid` to check if chunk is valid)
|
// undefined behaviour (use `isValid` to check if chunk is valid).
|
||||||
/// @param num Index of chunk to return
|
const RTCP_SDES_CHUNK *getChunk(int num) const;
|
||||||
inline RTCP_SDES_CHUNK *getChunk(int num) {
|
RTCP_SDES_CHUNK *getChunk(int num);
|
||||||
auto base = &_chunks;
|
|
||||||
while (num-- > 0) {
|
|
||||||
auto chunkSize = base->getSize();
|
|
||||||
base =
|
|
||||||
reinterpret_cast<RTCP_SDES_CHUNK *>(reinterpret_cast<uint8_t *>(base) + chunkSize);
|
|
||||||
}
|
|
||||||
return reinterpret_cast<RTCP_SDES_CHUNK *>(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size(const std::vector<std::vector<uint8_t>> lengths) {
|
void preparePacket(uint8_t chunkCount);
|
||||||
unsigned int chunks_size = 0;
|
|
||||||
for (auto length : lengths) {
|
|
||||||
chunks_size += RTCP_SDES_CHUNK::size(length);
|
|
||||||
}
|
|
||||||
return 4 + chunks_size;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_RR {
|
struct RTC_CPP_EXPORT RTCP_RR {
|
||||||
RTCP_HEADER header;
|
RTCP_HEADER header;
|
||||||
SSRC _senderSSRC;
|
|
||||||
|
|
||||||
private:
|
SSRC _senderSSRC;
|
||||||
RTCP_ReportBlock _reportBlocks;
|
RTCP_ReportBlock _reportBlocks;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] static size_t SizeWithReportBlocks(uint8_t reportCount);
|
||||||
[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
|
|
||||||
[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
|
|
||||||
return &_reportBlocks + num;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SSRC senderSSRC() const { return ntohl(_senderSSRC); }
|
SSRC senderSSRC() const;
|
||||||
inline void setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); }
|
bool isSenderReport();
|
||||||
|
bool isReceiverReport();
|
||||||
|
|
||||||
[[nodiscard]] inline size_t getSize() const {
|
[[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
|
||||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
[[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
|
||||||
return sizeof(uint32_t) * (1 + size_t(header.length()));
|
[[nodiscard]] size_t getSize() const;
|
||||||
}
|
|
||||||
|
|
||||||
inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) {
|
void preparePacket(SSRC senderSSRC, uint8_t reportCount);
|
||||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
void setSenderSSRC(SSRC ssrc);
|
||||||
size_t length = (sizeWithReportBlocks(reportCount) / 4) - 1;
|
|
||||||
header.prepareHeader(201, reportCount, uint16_t(length));
|
|
||||||
this->_senderSSRC = htonl(senderSSRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static size_t sizeWithReportBlocks(uint8_t reportCount) {
|
void log() const;
|
||||||
return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isSenderReport() { return header.payloadType() == 200; }
|
|
||||||
|
|
||||||
inline bool isReceiverReport() { return header.payloadType() == 201; }
|
|
||||||
|
|
||||||
inline void log() const {
|
|
||||||
header.log();
|
|
||||||
PLOG_VERBOSE << "RTCP RR: "
|
|
||||||
<< " SSRC=" << ntohl(_senderSSRC);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
|
||||||
getReportBlock(i)->log();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_REMB {
|
struct RTC_CPP_EXPORT RTCP_REMB {
|
||||||
RTCP_FB_HEADER header;
|
RTCP_FB_HEADER header;
|
||||||
|
|
||||||
/*! \brief Unique identifier ('R' 'E' 'M' 'B') */
|
char _id[4]; // Unique identifier ('R' 'E' 'M' 'B')
|
||||||
char id[4];
|
uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask)
|
||||||
|
SSRC _ssrc[1];
|
||||||
|
|
||||||
/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */
|
[[nodiscard]] static size_t SizeWithSSRCs(int count);
|
||||||
uint32_t bitrate;
|
|
||||||
|
|
||||||
SSRC ssrc[1];
|
[[nodiscard]] unsigned int getSize() const;
|
||||||
|
|
||||||
[[nodiscard]] unsigned int getSize() const {
|
void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate);
|
||||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
void setBitrate(unsigned int numSSRC, unsigned int in_bitrate);
|
||||||
return sizeof(uint32_t) * (1 + header.header.length());
|
void setSsrc(int iterator, SSRC newSssrc);
|
||||||
}
|
|
||||||
|
|
||||||
void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) {
|
|
||||||
|
|
||||||
// Report Count becomes the format here.
|
|
||||||
header.header.prepareHeader(206, 15, 0);
|
|
||||||
|
|
||||||
// Always zero.
|
|
||||||
header.setMediaSourceSSRC(0);
|
|
||||||
|
|
||||||
header.setPacketSenderSSRC(senderSSRC);
|
|
||||||
|
|
||||||
id[0] = 'R';
|
|
||||||
id[1] = 'E';
|
|
||||||
id[2] = 'M';
|
|
||||||
id[3] = 'B';
|
|
||||||
|
|
||||||
setBitrate(numSSRC, in_bitrate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
|
|
||||||
unsigned int exp = 0;
|
|
||||||
while (in_bitrate > pow(2, 18) - 1) {
|
|
||||||
exp++;
|
|
||||||
in_bitrate /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
|
||||||
header.header.setLength(
|
|
||||||
uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
|
|
||||||
|
|
||||||
this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); }
|
|
||||||
|
|
||||||
size_t static inline sizeWithSSRCs(int count) {
|
|
||||||
return sizeof(RTCP_REMB) + (count - 1) * sizeof(SSRC);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_PLI {
|
struct RTC_CPP_EXPORT RTCP_PLI {
|
||||||
RTCP_FB_HEADER header;
|
RTCP_FB_HEADER header;
|
||||||
|
|
||||||
void preparePacket(SSRC messageSSRC) {
|
[[nodiscard]] static unsigned int Size();
|
||||||
header.header.prepareHeader(206, 1, 2);
|
|
||||||
header.setPacketSenderSSRC(messageSSRC);
|
|
||||||
header.setMediaSourceSSRC(messageSSRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() { header.log(); }
|
void preparePacket(SSRC messageSSRC);
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size() { return sizeof(RTCP_FB_HEADER); }
|
void log() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_FIR_PART {
|
struct RTC_CPP_EXPORT RTCP_FIR_PART {
|
||||||
uint32_t ssrc;
|
uint32_t ssrc;
|
||||||
uint8_t seqNo;
|
uint8_t seqNo;
|
||||||
uint8_t dummy1;
|
uint8_t dummy1;
|
||||||
uint16_t dummy2;
|
uint16_t dummy2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_FIR {
|
struct RTC_CPP_EXPORT RTCP_FIR {
|
||||||
RTCP_FB_HEADER header;
|
RTCP_FB_HEADER header;
|
||||||
RTCP_FIR_PART parts[1];
|
RTCP_FIR_PART parts[1];
|
||||||
|
|
||||||
void preparePacket(SSRC messageSSRC, uint8_t seqNo) {
|
static unsigned int Size();
|
||||||
header.header.prepareHeader(206, 4, 2 + 2 * 1);
|
|
||||||
header.setPacketSenderSSRC(messageSSRC);
|
|
||||||
header.setMediaSourceSSRC(messageSSRC);
|
|
||||||
parts[0].ssrc = htonl(messageSSRC);
|
|
||||||
parts[0].seqNo = seqNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() { header.log(); }
|
void preparePacket(SSRC messageSSRC, uint8_t seqNo);
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size() {
|
void log() const;
|
||||||
return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RTCP_NACK_PART {
|
struct RTC_CPP_EXPORT RTCP_NACK_PART {
|
||||||
uint16_t _pid;
|
uint16_t _pid;
|
||||||
uint16_t _blp;
|
uint16_t _blp;
|
||||||
|
|
||||||
uint16_t getPID() { return ntohs(_pid); }
|
uint16_t pid();
|
||||||
uint16_t getBLP() { return ntohs(_blp); }
|
uint16_t blp();
|
||||||
|
|
||||||
void setPID(uint16_t pid) { _pid = htons(pid); }
|
void setPid(uint16_t pid);
|
||||||
void setBLP(uint16_t blp) { _blp = htons(blp); }
|
void setBlp(uint16_t blp);
|
||||||
|
|
||||||
std::vector<uint16_t> getSequenceNumbers() {
|
std::vector<uint16_t> getSequenceNumbers();
|
||||||
std::vector<uint16_t> result{};
|
|
||||||
result.reserve(17);
|
|
||||||
uint16_t pid = getPID();
|
|
||||||
result.push_back(pid);
|
|
||||||
uint16_t bitmask = getBLP();
|
|
||||||
uint16_t i = pid + 1;
|
|
||||||
while (bitmask > 0) {
|
|
||||||
if (bitmask & 0x1) {
|
|
||||||
result.push_back(i);
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
bitmask >>= 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RTCP_NACK {
|
struct RTC_CPP_EXPORT RTCP_NACK {
|
||||||
public:
|
|
||||||
RTCP_FB_HEADER header;
|
RTCP_FB_HEADER header;
|
||||||
RTCP_NACK_PART parts[1];
|
RTCP_NACK_PART parts[1];
|
||||||
|
|
||||||
public:
|
[[nodiscard]] static unsigned int Size(unsigned int discreteSeqNoCount);
|
||||||
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
|
|
||||||
header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount));
|
[[nodiscard]] unsigned int getSeqNoCount();
|
||||||
header.setMediaSourceSSRC(ssrc);
|
|
||||||
header.setPacketSenderSSRC(ssrc);
|
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a packet to the list of missing packets.
|
* Add a packet to the list of missing packets.
|
||||||
@ -668,71 +320,22 @@ public:
|
|||||||
* @param missingPacket The seq no of the missing packet. This will be added to the queue.
|
* @param missingPacket The seq no of the missing packet. This will be added to the queue.
|
||||||
* @return true if the packet has grown, false otherwise.
|
* @return true if the packet has grown, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket) {
|
bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket);
|
||||||
if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) {
|
|
||||||
parts[*fciCount].setPID(missingPacket);
|
|
||||||
parts[*fciCount].setBLP(0);
|
|
||||||
*fciPID = missingPacket;
|
|
||||||
(*fciCount)++;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// TODO SPEED!
|
|
||||||
uint16_t blp = parts[(*fciCount) - 1].getBLP();
|
|
||||||
uint16_t newBit = uint16_t(1u << (missingPacket - (1 + *fciPID)));
|
|
||||||
parts[(*fciCount) - 1].setBLP(blp | newBit);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int getSize(unsigned int discreteSeqNoCount) {
|
|
||||||
return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] unsigned int getSeqNoCount() { return header.header.length() - 2; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RTP_RTX {
|
struct RTC_CPP_EXPORT RTP_RTX {
|
||||||
private:
|
|
||||||
RTP header;
|
RTP header;
|
||||||
|
|
||||||
public:
|
[[nodiscard]] const char *getBody() const;
|
||||||
size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) {
|
[[nodiscard]] char *getBody();
|
||||||
memmove((char *)dest, (char *)this, header.getSize());
|
[[nodiscard]] size_t getBodySize(size_t totalSize) const;
|
||||||
dest->setSeqNumber(getOriginalSeqNo());
|
[[nodiscard]] size_t getSize() const;
|
||||||
dest->setPayloadType(originalPayloadType);
|
[[nodiscard]] uint16_t getOriginalSeqNo() const;
|
||||||
memmove(dest->getBody(), getBody(), getBodySize(totalSize));
|
|
||||||
return totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] uint16_t getOriginalSeqNo() const {
|
// Returns the new size of the packet
|
||||||
return ntohs(*(uint16_t *)(header.getBody()));
|
size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType);
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] char *getBody() { return header.getBody() + sizeof(uint16_t); }
|
size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType);
|
||||||
|
|
||||||
[[nodiscard]] const char *getBody() const { return header.getBody() + sizeof(uint16_t); }
|
|
||||||
|
|
||||||
[[nodiscard]] size_t getBodySize(size_t totalSize) {
|
|
||||||
return totalSize - (getBody() - reinterpret_cast<char *>(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] size_t getSize() const{
|
|
||||||
return header.getSize() + sizeof(uint16_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] RTP &getHeader() { return header; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the new size of the packet
|
|
||||||
*/
|
|
||||||
size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) {
|
|
||||||
header.setSeqNumber(getOriginalSeqNo());
|
|
||||||
header.setSsrc(originalSSRC);
|
|
||||||
header.setPayloadType(originalPayloadType);
|
|
||||||
// TODO, the -12 is the size of the header (which is variable!)
|
|
||||||
memmove(header.getBody(), getBody(), totalSize - getSize());
|
|
||||||
return totalSize - 2;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_RTP_PACKETIZATION_CONFIG_H
|
#ifndef RTC_RTP_PACKETIZATION_CONFIG_H
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_RTP_PACKETIZER_H
|
#ifndef RTC_RTP_PACKETIZER_H
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
@ -58,40 +60,35 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// callback with built-in synchronization
|
// callback with built-in synchronization
|
||||||
template <typename... Args> class synchronized_callback final {
|
template <typename... Args> class synchronized_callback {
|
||||||
public:
|
public:
|
||||||
synchronized_callback() = default;
|
synchronized_callback() = default;
|
||||||
synchronized_callback(synchronized_callback &&cb) { *this = std::move(cb); }
|
synchronized_callback(synchronized_callback &&cb) { *this = std::move(cb); }
|
||||||
synchronized_callback(const synchronized_callback &cb) { *this = cb; }
|
synchronized_callback(const synchronized_callback &cb) { *this = cb; }
|
||||||
synchronized_callback(std::function<void(Args...)> func) { *this = std::move(func); }
|
synchronized_callback(std::function<void(Args...)> func) { *this = std::move(func); }
|
||||||
~synchronized_callback() { *this = nullptr; }
|
virtual ~synchronized_callback() { *this = nullptr; }
|
||||||
|
|
||||||
synchronized_callback &operator=(synchronized_callback &&cb) {
|
synchronized_callback &operator=(synchronized_callback &&cb) {
|
||||||
std::scoped_lock lock(mutex, cb.mutex);
|
std::scoped_lock lock(mutex, cb.mutex);
|
||||||
callback = std::move(cb.callback);
|
set(std::exchange(cb.callback, nullptr));
|
||||||
cb.callback = nullptr;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized_callback &operator=(const synchronized_callback &cb) {
|
synchronized_callback &operator=(const synchronized_callback &cb) {
|
||||||
std::scoped_lock lock(mutex, cb.mutex);
|
std::scoped_lock lock(mutex, cb.mutex);
|
||||||
callback = cb.callback;
|
set(cb.callback);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized_callback &operator=(std::function<void(Args...)> func) {
|
synchronized_callback &operator=(std::function<void(Args...)> func) {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
callback = std::move(func);
|
set(std::move(func));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(Args... args) const {
|
bool operator()(Args... args) const {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
if (!callback)
|
return call(std::move(args)...);
|
||||||
return false;
|
|
||||||
|
|
||||||
callback(std::move(args)...);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const {
|
operator bool() const {
|
||||||
@ -103,11 +100,48 @@ public:
|
|||||||
return [this](Args... args) { (*this)(std::move(args)...); };
|
return [this](Args... args) { (*this)(std::move(args)...); };
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
virtual void set(std::function<void(Args...)> func) { callback = std::move(func); }
|
||||||
|
virtual bool call(Args... args) const {
|
||||||
|
if (!callback)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
callback(std::move(args)...);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::function<void(Args...)> callback;
|
std::function<void(Args...)> callback;
|
||||||
mutable std::recursive_mutex mutex;
|
mutable std::recursive_mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// callback with built-in synchronization and replay of the last missed call
|
||||||
|
template <typename... Args>
|
||||||
|
class synchronized_stored_callback final : public synchronized_callback<Args...> {
|
||||||
|
public:
|
||||||
|
template <typename... CArgs>
|
||||||
|
synchronized_stored_callback(CArgs &&...cargs)
|
||||||
|
: synchronized_callback<Args...>(std::forward<CArgs>(cargs)...) {}
|
||||||
|
~synchronized_stored_callback() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set(std::function<void(Args...)> func) {
|
||||||
|
synchronized_callback<Args...>::set(func);
|
||||||
|
if (func && stored) {
|
||||||
|
std::apply(func, std::move(*stored));
|
||||||
|
stored.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool call(Args... args) const {
|
||||||
|
if (!synchronized_callback<Args...>::call(args...))
|
||||||
|
stored.emplace(std::move(args)...);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutable std::optional<std::tuple<Args...>> stored;
|
||||||
|
};
|
||||||
|
|
||||||
// pimpl base class
|
// pimpl base class
|
||||||
template <typename T> using impl_ptr = std::shared_ptr<T>;
|
template <typename T> using impl_ptr = std::shared_ptr<T>;
|
||||||
template <typename T> class CheshireCat {
|
template <typename T> class CheshireCat {
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "candidate.hpp"
|
#include "candidate.hpp"
|
||||||
#include "globals.hpp"
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
523
src/capi.cpp
523
src/capi.cpp
@ -17,10 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
|
|
||||||
#include "rtc.hpp"
|
#include "rtc.hpp"
|
||||||
|
|
||||||
#include "plog/Formatters/FuncMessageFormatter.h"
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
@ -29,11 +28,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <codecvt>
|
|
||||||
#include <locale>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace rtc;
|
using namespace rtc;
|
||||||
using std::chrono::milliseconds;
|
using std::chrono::milliseconds;
|
||||||
|
|
||||||
@ -116,14 +110,14 @@ int emplaceTrack(shared_ptr<Track> ptr) {
|
|||||||
void erasePeerConnection(int pc) {
|
void erasePeerConnection(int pc) {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
if (peerConnectionMap.erase(pc) == 0)
|
if (peerConnectionMap.erase(pc) == 0)
|
||||||
throw std::invalid_argument("PeerConnection ID does not exist");
|
throw std::invalid_argument("Peer Connection ID does not exist");
|
||||||
userPointerMap.erase(pc);
|
userPointerMap.erase(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void eraseDataChannel(int dc) {
|
void eraseDataChannel(int dc) {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
if (dataChannelMap.erase(dc) == 0)
|
if (dataChannelMap.erase(dc) == 0)
|
||||||
throw std::invalid_argument("DataChannel ID does not exist");
|
throw std::invalid_argument("Data Channel ID does not exist");
|
||||||
userPointerMap.erase(dc);
|
userPointerMap.erase(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +140,7 @@ shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
|
|||||||
if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
|
if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
} else {
|
} else {
|
||||||
throw std::invalid_argument("RtcpSRReporter ID does not exist");
|
throw std::invalid_argument("RTCP SR reporter ID does not exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +154,7 @@ shared_ptr<MediaChainableHandler> getMediaChainableHandler(int id) {
|
|||||||
if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) {
|
if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
} else {
|
} else {
|
||||||
throw std::invalid_argument("RtcpChainableHandler ID does not exist");
|
throw std::invalid_argument("RTCP chainable handler ID does not exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,44 +163,31 @@ void emplaceMediaChainableHandler(shared_ptr<MediaChainableHandler> ptr, int tr)
|
|||||||
rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr));
|
rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<RtpPacketizationConfig> getRTPConfig(int id) {
|
shared_ptr<RtpPacketizationConfig> getRtpConfig(int id) {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
|
if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
} else {
|
} else {
|
||||||
throw std::invalid_argument("RTPConfiguration ID does not exist");
|
throw std::invalid_argument("RTP configuration ID does not exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void emplaceRTPConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) {
|
void emplaceRtpConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
rtpConfigMap.emplace(std::make_pair(tr, ptr));
|
rtpConfigMap.emplace(std::make_pair(tr, ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Description::Direction rtcDirectionToDirection(rtcDirection direction) {
|
|
||||||
switch (direction) {
|
|
||||||
case RTC_DIRECTION_SENDONLY:
|
|
||||||
return Description::Direction::SendOnly;
|
|
||||||
case RTC_DIRECTION_RECVONLY:
|
|
||||||
return Description::Direction::RecvOnly;
|
|
||||||
case RTC_DIRECTION_SENDRECV:
|
|
||||||
return Description::Direction::SendRecv;
|
|
||||||
case RTC_DIRECTION_INACTIVE:
|
|
||||||
return Description::Direction::Inactive;
|
|
||||||
default:
|
|
||||||
return Description::Direction::Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<RtpPacketizationConfig>
|
shared_ptr<RtpPacketizationConfig>
|
||||||
getNewRtpPacketizationConfig(uint32_t ssrc, const char *cname, uint8_t payloadType,
|
createRtpPacketizationConfig(const rtcPacketizationHandlerInit *init) {
|
||||||
uint32_t clockRate, uint16_t sequenceNumber, uint32_t timestamp) {
|
if (!init)
|
||||||
if (!cname) {
|
throw std::invalid_argument("Unexpected null pointer for packetization handler init");
|
||||||
throw std::invalid_argument("Unexpected null pointer for cname");
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, clockRate,
|
if (!init->cname)
|
||||||
sequenceNumber, timestamp);
|
throw std::invalid_argument("Unexpected null pointer for cname");
|
||||||
|
|
||||||
|
return std::make_shared<RtpPacketizationConfig>(init->ssrc, init->cname, init->payloadType,
|
||||||
|
init->clockRate, init->sequenceNumber,
|
||||||
|
init->timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RTC_ENABLE_MEDIA
|
#endif // RTC_ENABLE_MEDIA
|
||||||
@ -287,58 +268,16 @@ int copyAndReturn(binary b, char *buffer, int size) {
|
|||||||
return int(b.size());
|
return int(b.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
class plogAppender : public plog::IAppender {
|
|
||||||
public:
|
|
||||||
plogAppender(rtcLogCallbackFunc cb = nullptr) { setCallback(cb); }
|
|
||||||
|
|
||||||
plogAppender(plogAppender &&appender) : callback(nullptr) {
|
|
||||||
std::lock_guard lock(appender.callbackMutex);
|
|
||||||
std::swap(appender.callback, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCallback(rtcLogCallbackFunc cb) {
|
|
||||||
std::lock_guard lock(callbackMutex);
|
|
||||||
callback = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const plog::Record &record) override {
|
|
||||||
plog::Severity severity = record.getSeverity();
|
|
||||||
auto formatted = plog::FuncMessageFormatter::format(record);
|
|
||||||
formatted.pop_back(); // remove newline
|
|
||||||
#ifdef _WIN32
|
|
||||||
using convert_type = std::codecvt_utf8<wchar_t>;
|
|
||||||
std::wstring_convert<convert_type, wchar_t> converter;
|
|
||||||
std::string str = converter.to_bytes(formatted);
|
|
||||||
#else
|
|
||||||
std::string str = formatted;
|
|
||||||
#endif
|
|
||||||
std::lock_guard lock(callbackMutex);
|
|
||||||
if (callback)
|
|
||||||
callback(static_cast<rtcLogLevel>(record.getSeverity()), str.c_str());
|
|
||||||
else
|
|
||||||
std::cout << plog::severityToString(severity) << " " << str << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
rtcLogCallbackFunc callback;
|
|
||||||
std::mutex callbackMutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
|
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
|
||||||
static optional<plogAppender> appender;
|
LogCallback callback = nullptr;
|
||||||
const auto severity = static_cast<plog::Severity>(level);
|
if (cb)
|
||||||
std::lock_guard lock(mutex);
|
callback = [cb](LogLevel level, string message) {
|
||||||
if (appender) {
|
cb(static_cast<rtcLogLevel>(level), message.c_str());
|
||||||
appender->setCallback(cb);
|
};
|
||||||
InitLogger(severity, nullptr); // change the severity
|
|
||||||
} else if (cb) {
|
InitLogger(static_cast<LogLevel>(level), callback);
|
||||||
appender.emplace(plogAppender(cb));
|
|
||||||
InitLogger(severity, &appender.value());
|
|
||||||
} else {
|
|
||||||
InitLogger(severity, nullptr); // log to stdout
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); }
|
void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); }
|
||||||
@ -438,69 +377,65 @@ int rtcDeleteDataChannel(int dc) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
|
||||||
|
return wrap([&] {
|
||||||
|
if (!mediaDescriptionSdp)
|
||||||
|
throw std::invalid_argument("Unexpected null pointer for track media description");
|
||||||
|
|
||||||
void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid,
|
auto peerConnection = getPeerConnection(pc);
|
||||||
const char *_trackID) {
|
Description::Media media{string(mediaDescriptionSdp)};
|
||||||
|
int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
|
||||||
|
if (auto ptr = getUserPointer(pc))
|
||||||
|
rtcSetUserPointer(tr, *ptr);
|
||||||
|
|
||||||
optional<string> name = nullopt;
|
return tr;
|
||||||
if (_name) {
|
});
|
||||||
name = string(_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<string> msid = nullopt;
|
|
||||||
if (_msid) {
|
|
||||||
msid = string(_msid);
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<string> trackID = nullopt;
|
|
||||||
if (_trackID) {
|
|
||||||
trackID = string(_trackID);
|
|
||||||
}
|
|
||||||
|
|
||||||
description->addSSRC(ssrc, name, msid, trackID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid,
|
int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
|
||||||
rtcDirection _direction, const char *_name, const char *_msid,
|
|
||||||
const char *_trackID) {
|
|
||||||
return wrap([&] {
|
return wrap([&] {
|
||||||
auto peerConnection = getPeerConnection(pc);
|
auto peerConnection = getPeerConnection(pc);
|
||||||
|
|
||||||
auto direction = rtcDirectionToDirection(_direction);
|
if (!init)
|
||||||
|
throw std::invalid_argument("Unexpected null pointer for track init");
|
||||||
|
|
||||||
string mid = "video";
|
auto direction = static_cast<Description::Direction>(init->direction);
|
||||||
switch (codec) {
|
|
||||||
case RTC_CODEC_H264:
|
|
||||||
case RTC_CODEC_VP8:
|
|
||||||
case RTC_CODEC_VP9:
|
|
||||||
mid = "video";
|
|
||||||
break;
|
|
||||||
case RTC_CODEC_OPUS:
|
|
||||||
mid = "audio";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mid) {
|
string mid;
|
||||||
mid = string(_mid);
|
if (init->mid) {
|
||||||
|
mid = string(init->mid);
|
||||||
|
} else {
|
||||||
|
switch (init->codec) {
|
||||||
|
case RTC_CODEC_H264:
|
||||||
|
case RTC_CODEC_VP8:
|
||||||
|
case RTC_CODEC_VP9:
|
||||||
|
mid = "video";
|
||||||
|
break;
|
||||||
|
case RTC_CODEC_OPUS:
|
||||||
|
mid = "audio";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mid = "video";
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<Description::Media> optDescription = nullopt;
|
optional<Description::Media> optDescription = nullopt;
|
||||||
|
|
||||||
switch (codec) {
|
switch (init->codec) {
|
||||||
case RTC_CODEC_H264:
|
case RTC_CODEC_H264:
|
||||||
case RTC_CODEC_VP8:
|
case RTC_CODEC_VP8:
|
||||||
case RTC_CODEC_VP9: {
|
case RTC_CODEC_VP9: {
|
||||||
auto desc = Description::Video(mid, direction);
|
auto desc = Description::Video(mid, direction);
|
||||||
switch (codec) {
|
switch (init->codec) {
|
||||||
case RTC_CODEC_H264:
|
case RTC_CODEC_H264:
|
||||||
desc.addH264Codec(payloadType);
|
desc.addH264Codec(init->payloadType);
|
||||||
break;
|
break;
|
||||||
case RTC_CODEC_VP8:
|
case RTC_CODEC_VP8:
|
||||||
desc.addVP8Codec(payloadType);
|
desc.addVP8Codec(init->payloadType);
|
||||||
break;
|
break;
|
||||||
case RTC_CODEC_VP9:
|
case RTC_CODEC_VP9:
|
||||||
desc.addVP8Codec(payloadType);
|
desc.addVP8Codec(init->payloadType);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -510,9 +445,9 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
|
|||||||
}
|
}
|
||||||
case RTC_CODEC_OPUS: {
|
case RTC_CODEC_OPUS: {
|
||||||
auto desc = Description::Audio(mid, direction);
|
auto desc = Description::Audio(mid, direction);
|
||||||
switch (codec) {
|
switch (init->codec) {
|
||||||
case RTC_CODEC_OPUS:
|
case RTC_CODEC_OPUS:
|
||||||
desc.addOpusCodec(payloadType);
|
desc.addOpusCodec(init->payloadType);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -524,168 +459,16 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optDescription.has_value()) {
|
if (!optDescription)
|
||||||
throw std::invalid_argument("Unexpected codec");
|
throw std::invalid_argument("Unexpected codec");
|
||||||
} else {
|
|
||||||
auto description = optDescription.value();
|
|
||||||
setSSRC(&description, ssrc, _name, _msid, _trackID);
|
|
||||||
|
|
||||||
int tr = emplaceTrack(peerConnection->addTrack(std::move(description)));
|
auto desc = std::move(*optDescription);
|
||||||
if (auto ptr = getUserPointer(pc)) {
|
desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
|
||||||
rtcSetUserPointer(tr, *ptr);
|
init->msid ? std::make_optional(string(init->msid)) : nullopt,
|
||||||
}
|
init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
|
||||||
return tr;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char *cname, uint8_t payloadType,
|
int tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
|
||||||
uint32_t clockRate, uint16_t maxFragmentSize,
|
|
||||||
uint16_t sequenceNumber, uint32_t timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto track = getTrack(tr);
|
|
||||||
// create RTP configuration
|
|
||||||
auto rtpConfig = getNewRtpPacketizationConfig(ssrc, cname, payloadType, clockRate,
|
|
||||||
sequenceNumber, timestamp);
|
|
||||||
// create packetizer
|
|
||||||
auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
|
|
||||||
// create H264 handler
|
|
||||||
auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
|
|
||||||
emplaceMediaChainableHandler(h264Handler, tr);
|
|
||||||
emplaceRTPConfig(rtpConfig, tr);
|
|
||||||
// set handler
|
|
||||||
track->setMediaHandler(h264Handler);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char *cname, uint8_t payloadType,
|
|
||||||
uint32_t clockRate, uint16_t sequenceNumber,
|
|
||||||
uint32_t timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto track = getTrack(tr);
|
|
||||||
// create RTP configuration
|
|
||||||
auto rtpConfig = getNewRtpPacketizationConfig(ssrc, cname, payloadType, clockRate,
|
|
||||||
sequenceNumber, timestamp);
|
|
||||||
// create packetizer
|
|
||||||
auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
|
|
||||||
// create Opus handler
|
|
||||||
auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
|
|
||||||
emplaceMediaChainableHandler(opusHandler, tr);
|
|
||||||
emplaceRTPConfig(rtpConfig, tr);
|
|
||||||
// set handler
|
|
||||||
track->setMediaHandler(opusHandler);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcChainRtcpSrReporter(int tr) {
|
|
||||||
return wrap([tr] {
|
|
||||||
auto config = getRTPConfig(tr);
|
|
||||||
auto reporter = std::make_shared<RtcpSrReporter>(config);
|
|
||||||
emplaceRtcpSrReporter(reporter, tr);
|
|
||||||
auto chainableHandler = getMediaChainableHandler(tr);
|
|
||||||
chainableHandler->addToChain(reporter);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount) {
|
|
||||||
return wrap([tr, maxStoredPacketsCount] {
|
|
||||||
auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
|
|
||||||
auto chainableHandler = getMediaChainableHandler(tr);
|
|
||||||
chainableHandler->addToChain(responder);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970,
|
|
||||||
uint32_t timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto config = getRTPConfig(id);
|
|
||||||
auto epoch = RtpPacketizationConfig::EpochStart::T1900;
|
|
||||||
if (timeIntervalSince1970) {
|
|
||||||
epoch = RtpPacketizationConfig::EpochStart::T1970;
|
|
||||||
}
|
|
||||||
config->setStartTime(startTime_s, epoch, timestamp);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcStartRtcpSenderReporterRecording(int id) {
|
|
||||||
return wrap([id] {
|
|
||||||
auto sender = getRtcpSrReporter(id);
|
|
||||||
sender->startRecording();
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto config = getRTPConfig(id);
|
|
||||||
*timestamp = config->secondsToTimestamp(seconds);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto config = getRTPConfig(id);
|
|
||||||
*seconds = config->timestampToSeconds(timestamp);
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto config = getRTPConfig(id);
|
|
||||||
*timestamp = config->timestamp;
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto config = getRTPConfig(id);
|
|
||||||
*timestamp = config->startTimestamp;
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto config = getRTPConfig(id);
|
|
||||||
config->timestamp = timestamp;
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
|
|
||||||
return wrap([&] {
|
|
||||||
auto sender = getRtcpSrReporter(id);
|
|
||||||
*timestamp = sender->previousReportedTimestamp;
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtcSetNeedsToSendRtcpSr(int id) {
|
|
||||||
return wrap([id] {
|
|
||||||
auto sender = getRtcpSrReporter(id);
|
|
||||||
sender->setNeedsToReport();
|
|
||||||
return RTC_ERR_SUCCESS;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // RTC_ENABLE_MEDIA
|
|
||||||
|
|
||||||
int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
|
|
||||||
return wrap([&] {
|
|
||||||
if (!mediaDescriptionSdp)
|
|
||||||
throw std::invalid_argument("Unexpected null pointer for track media description");
|
|
||||||
|
|
||||||
auto peerConnection = getPeerConnection(pc);
|
|
||||||
Description::Media media{string(mediaDescriptionSdp)};
|
|
||||||
int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
|
|
||||||
if (auto ptr = getUserPointer(pc))
|
if (auto ptr = getUserPointer(pc))
|
||||||
rtcSetUserPointer(tr, *ptr);
|
rtcSetUserPointer(tr, *ptr);
|
||||||
|
|
||||||
@ -715,7 +498,141 @@ int rtcGetTrackDescription(int tr, char *buffer, int size) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
|
int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto track = getTrack(tr);
|
||||||
|
// create RTP configuration
|
||||||
|
auto rtpConfig = createRtpPacketizationConfig(init);
|
||||||
|
// create packetizer
|
||||||
|
auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize
|
||||||
|
: RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE;
|
||||||
|
auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
|
||||||
|
// create H264 handler
|
||||||
|
auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
|
||||||
|
emplaceMediaChainableHandler(h264Handler, tr);
|
||||||
|
emplaceRtpConfig(rtpConfig, tr);
|
||||||
|
// set handler
|
||||||
|
track->setMediaHandler(h264Handler);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto track = getTrack(tr);
|
||||||
|
// create RTP configuration
|
||||||
|
auto rtpConfig = createRtpPacketizationConfig(init);
|
||||||
|
// create packetizer
|
||||||
|
auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
|
||||||
|
// create Opus handler
|
||||||
|
auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
|
||||||
|
emplaceMediaChainableHandler(opusHandler, tr);
|
||||||
|
emplaceRtpConfig(rtpConfig, tr);
|
||||||
|
// set handler
|
||||||
|
track->setMediaHandler(opusHandler);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcChainRtcpSrReporter(int tr) {
|
||||||
|
return wrap([tr] {
|
||||||
|
auto config = getRtpConfig(tr);
|
||||||
|
auto reporter = std::make_shared<RtcpSrReporter>(config);
|
||||||
|
emplaceRtcpSrReporter(reporter, tr);
|
||||||
|
auto chainableHandler = getMediaChainableHandler(tr);
|
||||||
|
chainableHandler->addToChain(reporter);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
|
||||||
|
return wrap([tr, maxStoredPacketsCount] {
|
||||||
|
auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
|
||||||
|
auto chainableHandler = getMediaChainableHandler(tr);
|
||||||
|
chainableHandler->addToChain(responder);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto config = getRtpConfig(id);
|
||||||
|
auto epoch = startTime->since1970 ? RtpPacketizationConfig::EpochStart::T1970
|
||||||
|
: RtpPacketizationConfig::EpochStart::T1900;
|
||||||
|
config->setStartTime(startTime->seconds, epoch, startTime->timestamp);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcStartRtcpSenderReporterRecording(int id) {
|
||||||
|
return wrap([id] {
|
||||||
|
auto sender = getRtcpSrReporter(id);
|
||||||
|
sender->startRecording();
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto config = getRtpConfig(id);
|
||||||
|
*timestamp = config->secondsToTimestamp(seconds);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto config = getRtpConfig(id);
|
||||||
|
*seconds = config->timestampToSeconds(timestamp);
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto config = getRtpConfig(id);
|
||||||
|
*timestamp = config->timestamp;
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto config = getRtpConfig(id);
|
||||||
|
*timestamp = config->startTimestamp;
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto config = getRtpConfig(id);
|
||||||
|
config->timestamp = timestamp;
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
|
||||||
|
return wrap([&] {
|
||||||
|
auto sender = getRtcpSrReporter(id);
|
||||||
|
*timestamp = sender->previousReportedTimestamp;
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcSetNeedsToSendRtcpSr(int id) {
|
||||||
|
return wrap([id] {
|
||||||
|
auto sender = getRtcpSrReporter(id);
|
||||||
|
sender->setNeedsToReport();
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // RTC_ENABLE_MEDIA
|
||||||
#if RTC_ENABLE_WEBSOCKET
|
#if RTC_ENABLE_WEBSOCKET
|
||||||
|
|
||||||
int rtcCreateWebSocket(const char *url) {
|
int rtcCreateWebSocket(const char *url) {
|
||||||
return wrap([&] {
|
return wrap([&] {
|
||||||
auto ws = std::make_shared<WebSocket>();
|
auto ws = std::make_shared<WebSocket>();
|
||||||
@ -748,6 +665,7 @@ int rtcDeleteWebsocket(int ws) {
|
|||||||
return RTC_ERR_SUCCESS;
|
return RTC_ERR_SUCCESS;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
|
int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
|
||||||
@ -1189,4 +1107,37 @@ int rtcReceiveMessage(int id, char *buffer, int *size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rtcPreload() { rtc::Preload(); }
|
void rtcPreload() { rtc::Preload(); }
|
||||||
|
|
||||||
void rtcCleanup() { rtc::Cleanup(); }
|
void rtcCleanup() { rtc::Cleanup(); }
|
||||||
|
|
||||||
|
int rtcSetSctpSettings(const rtcSctpSettings *settings) {
|
||||||
|
return wrap([&] {
|
||||||
|
SctpSettings s = {};
|
||||||
|
|
||||||
|
if (settings->recvBufferSize > 0)
|
||||||
|
s.recvBufferSize = size_t(settings->recvBufferSize);
|
||||||
|
|
||||||
|
if (settings->sendBufferSize > 0)
|
||||||
|
s.sendBufferSize = size_t(settings->sendBufferSize);
|
||||||
|
|
||||||
|
if (settings->maxChunksOnQueue > 0)
|
||||||
|
s.maxChunksOnQueue = size_t(settings->maxChunksOnQueue);
|
||||||
|
|
||||||
|
if (settings->initialCongestionWindow > 0)
|
||||||
|
s.initialCongestionWindow = size_t(settings->initialCongestionWindow);
|
||||||
|
|
||||||
|
if (settings->maxBurst > 0)
|
||||||
|
s.maxBurst = size_t(settings->maxBurst);
|
||||||
|
else if (settings->maxBurst < 0)
|
||||||
|
s.maxBurst = size_t(0); // setting to 0 disables, not setting chooses optimized default
|
||||||
|
|
||||||
|
if (settings->congestionControlModule >= 0)
|
||||||
|
s.congestionControlModule = unsigned(settings->congestionControlModule);
|
||||||
|
|
||||||
|
if (settings->delayedSackTimeMs > 0)
|
||||||
|
s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
|
||||||
|
|
||||||
|
SetSctpSettings(std::move(s));
|
||||||
|
return RTC_ERR_SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "channel.hpp"
|
#include "channel.hpp"
|
||||||
#include "globals.hpp"
|
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
#include "impl/channel.hpp"
|
#include "impl/channel.hpp"
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
@ -43,10 +43,7 @@ void Channel::onError(std::function<void(string error)> callback) {
|
|||||||
|
|
||||||
void Channel::onMessage(std::function<void(message_variant data)> callback) {
|
void Channel::onMessage(std::function<void(message_variant data)> callback) {
|
||||||
impl()->messageCallback = callback;
|
impl()->messageCallback = callback;
|
||||||
|
impl()->flushPendingMessages();
|
||||||
// Pass pending messages
|
|
||||||
while (auto message = receive())
|
|
||||||
impl()->messageCallback(*message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Channel::onMessage(std::function<void(binary data)> binaryCallback,
|
void Channel::onMessage(std::function<void(binary data)> binaryCallback,
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "datachannel.hpp"
|
#include "datachannel.hpp"
|
||||||
#include "globals.hpp"
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "peerconnection.hpp"
|
#include "peerconnection.hpp"
|
||||||
|
|
||||||
#include "impl/datachannel.hpp"
|
#include "impl/datachannel.hpp"
|
||||||
|
#include "impl/internals.hpp"
|
||||||
#include "impl/peerconnection.hpp"
|
#include "impl/peerconnection.hpp"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "description.hpp"
|
#include "description.hpp"
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
95
src/global.cpp
Normal file
95
src/global.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2020-2021 Paul-Louis Ageneau
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "plog/Appenders/ColorConsoleAppender.h"
|
||||||
|
#include "plog/Formatters/FuncMessageFormatter.h"
|
||||||
|
#include "plog/Formatters/TxtFormatter.h"
|
||||||
|
#include "plog/Init.h"
|
||||||
|
#include "plog/Log.h"
|
||||||
|
#include "plog/Logger.h"
|
||||||
|
//
|
||||||
|
#include "global.hpp"
|
||||||
|
|
||||||
|
#include "impl/init.hpp"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace rtc {
|
||||||
|
|
||||||
|
struct LogAppender : public plog::IAppender {
|
||||||
|
synchronized_callback<LogLevel, string> callback;
|
||||||
|
|
||||||
|
void write(const plog::Record &record) override {
|
||||||
|
const auto severity = record.getSeverity();
|
||||||
|
auto formatted = plog::FuncMessageFormatter::format(record);
|
||||||
|
formatted.pop_back(); // remove newline
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
using convert_type = std::codecvt_utf8<wchar_t>;
|
||||||
|
std::wstring_convert<convert_type, wchar_t> converter;
|
||||||
|
std::string str = converter.to_bytes(formatted);
|
||||||
|
#else
|
||||||
|
std::string str = formatted;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!callback(static_cast<LogLevel>(severity), str))
|
||||||
|
std::cout << plog::severityToString(severity) << " " << str << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitLogger(LogLevel level, LogCallback callback) {
|
||||||
|
static unique_ptr<LogAppender> appender;
|
||||||
|
const auto severity = static_cast<plog::Severity>(level);
|
||||||
|
if (appender) {
|
||||||
|
appender->callback = std::move(callback);
|
||||||
|
InitLogger(severity, nullptr); // change the severity
|
||||||
|
} else if (callback) {
|
||||||
|
appender = std::make_unique<LogAppender>();
|
||||||
|
appender->callback = std::move(callback);
|
||||||
|
InitLogger(severity, appender.get());
|
||||||
|
} else {
|
||||||
|
InitLogger(severity, nullptr); // log to cout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitLogger(plog::Severity severity, plog::IAppender *appender) {
|
||||||
|
static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
|
||||||
|
static plog::Logger<0> *logger = nullptr;
|
||||||
|
static std::mutex mutex;
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
if (!logger) {
|
||||||
|
logger = &plog::init(severity, appender ? appender : &consoleAppender);
|
||||||
|
PLOG_DEBUG << "Logger initialized";
|
||||||
|
} else {
|
||||||
|
logger->setMaxSeverity(severity);
|
||||||
|
if (appender)
|
||||||
|
logger->addAppender(appender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preload() { Init::Preload(); }
|
||||||
|
void Cleanup() { Init::Cleanup(); }
|
||||||
|
|
||||||
|
void SetSctpSettings(SctpSettings s) { Init::SetSctpSettings(std::move(s)); }
|
||||||
|
|
||||||
|
} // namespace rtc
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel client example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
@ -1,25 +1,35 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "h264rtppacketizer.hpp"
|
#include "h264rtppacketizer.hpp"
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -20,22 +20,21 @@
|
|||||||
|
|
||||||
namespace rtc::impl {
|
namespace rtc::impl {
|
||||||
|
|
||||||
void Channel::triggerOpen() { openCallback(); }
|
void Channel::triggerOpen() {
|
||||||
|
mOpenTriggered = true;
|
||||||
|
openCallback();
|
||||||
|
flushPendingMessages();
|
||||||
|
}
|
||||||
|
|
||||||
void Channel::triggerClosed() { closedCallback(); }
|
void Channel::triggerClosed() { closedCallback(); }
|
||||||
|
|
||||||
void Channel::triggerError(string error) { errorCallback(error); }
|
void Channel::triggerError(string error) { errorCallback(std::move(error)); }
|
||||||
|
|
||||||
void Channel::triggerAvailable(size_t count) {
|
void Channel::triggerAvailable(size_t count) {
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
availableCallback();
|
availableCallback();
|
||||||
|
|
||||||
while (messageCallback && count--) {
|
flushPendingMessages();
|
||||||
auto message = receive();
|
|
||||||
if (!message)
|
|
||||||
break;
|
|
||||||
messageCallback(*message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Channel::triggerBufferedAmount(size_t amount) {
|
void Channel::triggerBufferedAmount(size_t amount) {
|
||||||
@ -45,13 +44,32 @@ void Channel::triggerBufferedAmount(size_t amount) {
|
|||||||
bufferedAmountLowCallback();
|
bufferedAmountLowCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Channel::flushPendingMessages() {
|
||||||
|
if (!mOpenTriggered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (messageCallback) {
|
||||||
|
auto next = receive();
|
||||||
|
if (!next)
|
||||||
|
break;
|
||||||
|
|
||||||
|
messageCallback(*next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Channel::resetOpenCallback() {
|
||||||
|
mOpenTriggered = false;
|
||||||
|
openCallback = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Channel::resetCallbacks() {
|
void Channel::resetCallbacks() {
|
||||||
|
mOpenTriggered = false;
|
||||||
openCallback = nullptr;
|
openCallback = nullptr;
|
||||||
closedCallback = nullptr;
|
closedCallback = nullptr;
|
||||||
errorCallback = nullptr;
|
errorCallback = nullptr;
|
||||||
messageCallback = nullptr;
|
|
||||||
availableCallback = nullptr;
|
availableCallback = nullptr;
|
||||||
bufferedAmountLowCallback = nullptr;
|
bufferedAmountLowCallback = nullptr;
|
||||||
|
messageCallback = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rtc::impl
|
} // namespace rtc::impl
|
||||||
|
@ -38,17 +38,23 @@ struct Channel {
|
|||||||
virtual void triggerAvailable(size_t count);
|
virtual void triggerAvailable(size_t count);
|
||||||
virtual void triggerBufferedAmount(size_t amount);
|
virtual void triggerBufferedAmount(size_t amount);
|
||||||
|
|
||||||
virtual void resetCallbacks();
|
void flushPendingMessages();
|
||||||
|
void resetOpenCallback();
|
||||||
|
void resetCallbacks();
|
||||||
|
|
||||||
|
synchronized_stored_callback<> openCallback;
|
||||||
|
synchronized_stored_callback<> closedCallback;
|
||||||
|
synchronized_stored_callback<string> errorCallback;
|
||||||
|
synchronized_stored_callback<> availableCallback;
|
||||||
|
synchronized_stored_callback<> bufferedAmountLowCallback;
|
||||||
|
|
||||||
synchronized_callback<> openCallback;
|
|
||||||
synchronized_callback<> closedCallback;
|
|
||||||
synchronized_callback<string> errorCallback;
|
|
||||||
synchronized_callback<message_variant> messageCallback;
|
synchronized_callback<message_variant> messageCallback;
|
||||||
synchronized_callback<> availableCallback;
|
|
||||||
synchronized_callback<> bufferedAmountLowCallback;
|
|
||||||
|
|
||||||
std::atomic<size_t> bufferedAmount = 0;
|
std::atomic<size_t> bufferedAmount = 0;
|
||||||
std::atomic<size_t> bufferedAmountLowThreshold = 0;
|
std::atomic<size_t> bufferedAmountLowThreshold = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<bool> mOpenTriggered = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rtc::impl
|
} // namespace rtc::impl
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "datachannel.hpp"
|
#include "datachannel.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "logcounter.hpp"
|
#include "logcounter.hpp"
|
||||||
#include "peerconnection.hpp"
|
#include "peerconnection.hpp"
|
||||||
#include "sctptransport.hpp"
|
#include "sctptransport.hpp"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dtlstransport.hpp"
|
#include "dtlstransport.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "icetransport.hpp"
|
#include "icetransport.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "icetransport.hpp"
|
#include "icetransport.hpp"
|
||||||
#include "configuration.hpp"
|
#include "configuration.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "transport.hpp"
|
#include "transport.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "init.hpp"
|
#include "init.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
|
|
||||||
#include "impl/certificate.hpp"
|
#include "impl/certificate.hpp"
|
||||||
#include "impl/dtlstransport.hpp"
|
#include "impl/dtlstransport.hpp"
|
||||||
@ -42,7 +42,6 @@ namespace rtc {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void doInit() {
|
void doInit() {
|
||||||
PLOG_DEBUG << "Global initialization";
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
@ -69,8 +68,6 @@ void doInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void doCleanup() {
|
void doCleanup() {
|
||||||
PLOG_DEBUG << "Global cleanup";
|
|
||||||
|
|
||||||
impl::ThreadPool::Instance().join();
|
impl::ThreadPool::Instance().join();
|
||||||
|
|
||||||
impl::SctpTransport::Cleanup();
|
impl::SctpTransport::Cleanup();
|
||||||
@ -92,6 +89,7 @@ void doCleanup() {
|
|||||||
weak_ptr<void> Init::Weak;
|
weak_ptr<void> Init::Weak;
|
||||||
shared_ptr<void> *Init::Global = nullptr;
|
shared_ptr<void> *Init::Global = nullptr;
|
||||||
bool Init::Initialized = false;
|
bool Init::Initialized = false;
|
||||||
|
SctpSettings Init::CurrentSctpSettings = {};
|
||||||
std::recursive_mutex Init::Mutex;
|
std::recursive_mutex Init::Mutex;
|
||||||
|
|
||||||
init_token Init::Token() {
|
init_token Init::Token() {
|
||||||
@ -118,10 +116,20 @@ void Init::Cleanup() {
|
|||||||
Global = nullptr;
|
Global = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Init::SetSctpSettings(SctpSettings s) {
|
||||||
|
auto token = Token();
|
||||||
|
std::unique_lock lock(Mutex);
|
||||||
|
impl::SctpTransport::SetSettings(s);
|
||||||
|
CurrentSctpSettings = std::move(s); // store for next init
|
||||||
|
}
|
||||||
|
|
||||||
Init::Init() {
|
Init::Init() {
|
||||||
// Mutex is locked by Token() here
|
// Mutex is locked by Token() here
|
||||||
if (!std::exchange(Initialized, true))
|
if (!std::exchange(Initialized, true)) {
|
||||||
|
PLOG_DEBUG << "Global initialization";
|
||||||
doInit();
|
doInit();
|
||||||
|
impl::SctpTransport::SetSettings(CurrentSctpSettings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Init::~Init() {
|
Init::~Init() {
|
||||||
@ -130,8 +138,11 @@ Init::~Init() {
|
|||||||
std::unique_lock lock(Mutex);
|
std::unique_lock lock(Mutex);
|
||||||
if (Global)
|
if (Global)
|
||||||
return;
|
return;
|
||||||
if (std::exchange(Initialized, false))
|
|
||||||
|
if (std::exchange(Initialized, false)) {
|
||||||
|
PLOG_DEBUG << "Global cleanup";
|
||||||
doCleanup();
|
doCleanup();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
t.detach();
|
t.detach();
|
||||||
}
|
}
|
@ -16,22 +16,25 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_INIT_H
|
#ifndef RTC_IMPL_INIT_H
|
||||||
#define RTC_INIT_H
|
#define RTC_IMPL_INIT_H
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "global.hpp" // for SctpSettings
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
using init_token = shared_ptr<void>;
|
using init_token = shared_ptr<void>;
|
||||||
|
|
||||||
class RTC_CPP_EXPORT Init {
|
class Init {
|
||||||
public:
|
public:
|
||||||
static init_token Token();
|
static init_token Token();
|
||||||
static void Preload();
|
static void Preload();
|
||||||
static void Cleanup();
|
static void Cleanup();
|
||||||
|
static void SetSctpSettings(SctpSettings s);
|
||||||
|
|
||||||
~Init();
|
~Init();
|
||||||
|
|
||||||
@ -41,12 +44,10 @@ private:
|
|||||||
static weak_ptr<void> Weak;
|
static weak_ptr<void> Weak;
|
||||||
static shared_ptr<void> *Global;
|
static shared_ptr<void> *Global;
|
||||||
static bool Initialized;
|
static bool Initialized;
|
||||||
|
static SctpSettings CurrentSctpSettings;
|
||||||
static std::recursive_mutex Mutex;
|
static std::recursive_mutex Mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void Preload() { Init::Preload(); }
|
|
||||||
inline void Cleanup() { Init::Cleanup(); }
|
|
||||||
|
|
||||||
} // namespace rtc
|
} // namespace rtc
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -16,17 +16,33 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RTC_GLOBALS_H
|
#ifndef RTC_IMPL_INTERNALS_H
|
||||||
#define RTC_GLOBALS_H
|
#define RTC_IMPL_INTERNALS_H
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
|
// Disable warnings before including plog
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wall"
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma warning(push, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "plog/Log.h"
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length
|
const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length
|
||||||
const size_t MAX_NUMERICSERV_LEN = 6; // Max port string representation length
|
const size_t MAX_NUMERICSERV_LEN = 6; // Max port string representation length
|
||||||
|
|
||||||
const uint16_t DEFAULT_SCTP_PORT = 5000; // SCTP port to use by default
|
const uint16_t DEFAULT_SCTP_PORT = 5000; // SCTP port to use by default
|
||||||
|
|
||||||
const size_t DEFAULT_LOCAL_MAX_MESSAGE_SIZE = 256 * 1024; // Default local max message size
|
const size_t DEFAULT_LOCAL_MAX_MESSAGE_SIZE = 256 * 1024; // Default local max message size
|
||||||
const size_t DEFAULT_MAX_MESSAGE_SIZE = 65536; // Remote max message size if not specified in SDP
|
const size_t DEFAULT_MAX_MESSAGE_SIZE = 65536; // Remote max message size if not specified in SDP
|
@ -21,7 +21,7 @@
|
|||||||
#include "certificate.hpp"
|
#include "certificate.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "dtlstransport.hpp"
|
#include "dtlstransport.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "icetransport.hpp"
|
#include "icetransport.hpp"
|
||||||
#include "logcounter.hpp"
|
#include "logcounter.hpp"
|
||||||
#include "peerconnection.hpp"
|
#include "peerconnection.hpp"
|
||||||
@ -440,8 +440,8 @@ void PeerConnection::forwardMedia(message_ptr message) {
|
|||||||
offset += header->lengthInBytes();
|
offset += header->lengthInBytes();
|
||||||
if (header->payloadType() == 205 || header->payloadType() == 206) {
|
if (header->payloadType() == 205 || header->payloadType() == 206) {
|
||||||
auto rtcpfb = reinterpret_cast<RTCP_FB_HEADER *>(header);
|
auto rtcpfb = reinterpret_cast<RTCP_FB_HEADER *>(header);
|
||||||
ssrcs.insert(rtcpfb->getPacketSenderSSRC());
|
ssrcs.insert(rtcpfb->packetSenderSSRC());
|
||||||
ssrcs.insert(rtcpfb->getMediaSourceSSRC());
|
ssrcs.insert(rtcpfb->mediaSourceSSRC());
|
||||||
|
|
||||||
} else if (header->payloadType() == 200 || header->payloadType() == 201) {
|
} else if (header->payloadType() == 200 || header->payloadType() == 201) {
|
||||||
auto rtcpsr = reinterpret_cast<RTCP_SR *>(header);
|
auto rtcpsr = reinterpret_cast<RTCP_SR *>(header);
|
||||||
@ -973,33 +973,54 @@ string PeerConnection::localBundleMid() const {
|
|||||||
|
|
||||||
void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
|
void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
|
||||||
auto dataChannel = weakDataChannel.lock();
|
auto dataChannel = weakDataChannel.lock();
|
||||||
if (dataChannel)
|
if (dataChannel) {
|
||||||
|
dataChannel->resetOpenCallback(); // might be set internally
|
||||||
mPendingDataChannels.push(std::move(dataChannel));
|
mPendingDataChannels.push(std::move(dataChannel));
|
||||||
|
}
|
||||||
|
triggerPendingDataChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::triggerTrack(weak_ptr<Track> weakTrack) {
|
||||||
|
auto track = weakTrack.lock();
|
||||||
|
if (track) {
|
||||||
|
track->resetOpenCallback(); // might be set internally
|
||||||
|
mPendingTracks.push(std::move(track));
|
||||||
|
}
|
||||||
|
triggerPendingTracks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::triggerPendingDataChannels() {
|
||||||
while (dataChannelCallback) {
|
while (dataChannelCallback) {
|
||||||
auto next = mPendingDataChannels.tryPop();
|
auto next = mPendingDataChannels.tryPop();
|
||||||
if (!next)
|
if (!next)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mProcessor->enqueue(dataChannelCallback.wrap(),
|
auto impl = std::move(*next);
|
||||||
std::make_shared<rtc::DataChannel>(std::move(*next)));
|
dataChannelCallback(std::make_shared<rtc::DataChannel>(impl));
|
||||||
|
impl->triggerOpen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerConnection::triggerTrack(weak_ptr<Track> weakTrack) {
|
void PeerConnection::triggerPendingTracks() {
|
||||||
auto track = weakTrack.lock();
|
|
||||||
if (track)
|
|
||||||
mPendingTracks.push(std::move(track));
|
|
||||||
|
|
||||||
while (trackCallback) {
|
while (trackCallback) {
|
||||||
auto next = mPendingTracks.tryPop();
|
auto next = mPendingTracks.tryPop();
|
||||||
if (!next)
|
if (!next)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mProcessor->enqueue(trackCallback.wrap(), std::make_shared<rtc::Track>(std::move(*next)));
|
auto impl = std::move(*next);
|
||||||
|
trackCallback(std::make_shared<rtc::Track>(impl));
|
||||||
|
impl->triggerOpen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerConnection::flushPendingDataChannels() {
|
||||||
|
mProcessor->enqueue(std::bind(&PeerConnection::triggerPendingDataChannels, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::flushPendingTracks() {
|
||||||
|
mProcessor->enqueue(std::bind(&PeerConnection::triggerPendingTracks, this));
|
||||||
|
}
|
||||||
|
|
||||||
bool PeerConnection::changeState(State newState) {
|
bool PeerConnection::changeState(State newState) {
|
||||||
State current;
|
State current;
|
||||||
do {
|
do {
|
||||||
|
@ -84,8 +84,14 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
|
|||||||
void processRemoteCandidate(Candidate candidate);
|
void processRemoteCandidate(Candidate candidate);
|
||||||
string localBundleMid() const;
|
string localBundleMid() const;
|
||||||
|
|
||||||
void triggerDataChannel(weak_ptr<DataChannel> weakDataChannel = {});
|
void triggerDataChannel(weak_ptr<DataChannel> weakDataChannel);
|
||||||
void triggerTrack(weak_ptr<Track> weakTrack = {});
|
void triggerTrack(weak_ptr<Track> weakTrack);
|
||||||
|
|
||||||
|
void triggerPendingDataChannels();
|
||||||
|
void triggerPendingTracks();
|
||||||
|
|
||||||
|
void flushPendingDataChannels();
|
||||||
|
void flushPendingTracks();
|
||||||
|
|
||||||
bool changeState(State newState);
|
bool changeState(State newState);
|
||||||
bool changeGatheringState(GatheringState newState);
|
bool changeGatheringState(GatheringState newState);
|
||||||
|
@ -18,12 +18,13 @@
|
|||||||
|
|
||||||
#include "sctptransport.hpp"
|
#include "sctptransport.hpp"
|
||||||
#include "dtlstransport.hpp"
|
#include "dtlstransport.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "logcounter.hpp"
|
#include "logcounter.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -54,6 +55,26 @@
|
|||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename T> uint16_t to_uint16(T i) {
|
||||||
|
if (i >= 0 && static_cast<typename std::make_unsigned<T>::type>(i) <=
|
||||||
|
std::numeric_limits<uint16_t>::max())
|
||||||
|
return static_cast<uint16_t>(i);
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("Integer out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> uint32_t to_uint32(T i) {
|
||||||
|
if (i >= 0 && static_cast<typename std::make_unsigned<T>::type>(i) <=
|
||||||
|
std::numeric_limits<uint32_t>::max())
|
||||||
|
return static_cast<uint32_t>(i);
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("Integer out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace rtc::impl {
|
namespace rtc::impl {
|
||||||
|
|
||||||
static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
|
static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
|
||||||
@ -69,7 +90,8 @@ std::shared_mutex SctpTransport::InstancesMutex;
|
|||||||
|
|
||||||
void SctpTransport::Init() {
|
void SctpTransport::Init() {
|
||||||
usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
|
usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
|
||||||
usrsctp_sysctl_set_sctp_ecn_enable(0);
|
usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758)
|
||||||
|
usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification
|
||||||
usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
|
usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
|
||||||
usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
|
usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
|
||||||
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path
|
usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path
|
||||||
@ -78,21 +100,31 @@ void SctpTransport::Init() {
|
|||||||
usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms
|
usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms
|
||||||
usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms
|
usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms
|
||||||
usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
|
usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
|
||||||
|
}
|
||||||
|
|
||||||
usrsctp_sysctl_set_sctp_max_chunks_on_queue(10 * 1024);
|
void SctpTransport::SetSettings(const SctpSettings &s) {
|
||||||
|
// The send and receive window size of usrsctp is 256KiB, which is too small for realistic RTTs,
|
||||||
|
// therefore we increase it to 1MiB by default for better performance.
|
||||||
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
|
||||||
|
usrsctp_sysctl_set_sctp_recvspace(to_uint32(s.recvBufferSize.value_or(1024 * 1024)));
|
||||||
|
usrsctp_sysctl_set_sctp_sendspace(to_uint32(s.sendBufferSize.value_or(1024 * 1024)));
|
||||||
|
|
||||||
// Use default congestion control (RFC 4960)
|
// Increase maximum chunks number on queue to 10K by default
|
||||||
|
usrsctp_sysctl_set_sctp_max_chunks_on_queue(to_uint32(s.maxChunksOnQueue.value_or(10 * 1024)));
|
||||||
|
|
||||||
|
// Increase initial congestion window size to 10 MTUs (RFC 6928) by default
|
||||||
|
usrsctp_sysctl_set_sctp_initial_cwnd(to_uint32(s.initialCongestionWindow.value_or(10)));
|
||||||
|
|
||||||
|
// Set max burst to 10 MTUs by default (max burst is initially 0, meaning disabled)
|
||||||
|
usrsctp_sysctl_set_sctp_max_burst_default(to_uint32(s.maxBurst.value_or(10)));
|
||||||
|
|
||||||
|
// Use standard SCTP congestion control (RFC 4960) by default
|
||||||
// See https://github.com/paullouisageneau/libdatachannel/issues/354
|
// See https://github.com/paullouisageneau/libdatachannel/issues/354
|
||||||
usrsctp_sysctl_set_sctp_default_cc_module(0);
|
usrsctp_sysctl_set_sctp_default_cc_module(to_uint32(s.congestionControlModule.value_or(0)));
|
||||||
|
|
||||||
// Enable Partial Reliability Extension (RFC 3758)
|
// Reduce SACK delay to 20ms by default
|
||||||
usrsctp_sysctl_set_sctp_pr_enable(1);
|
usrsctp_sysctl_set_sctp_delayed_sack_time_default(
|
||||||
|
to_uint32(s.delayedSackTime.value_or(20ms).count()));
|
||||||
// Increase the initial window size to 10 MTUs (RFC 6928)
|
|
||||||
usrsctp_sysctl_set_sctp_initial_cwnd(10);
|
|
||||||
|
|
||||||
// Reduce SACK delay from the default 200ms to 20ms
|
|
||||||
usrsctp_sysctl_set_sctp_delayed_sack_time_default(20); // ms
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SctpTransport::Cleanup() {
|
void SctpTransport::Cleanup() {
|
||||||
@ -195,7 +227,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
|
|||||||
// The MTU value provided specifies the space available for chunks in the
|
// The MTU value provided specifies the space available for chunks in the
|
||||||
// packet, so we also subtract the SCTP header size.
|
// packet, so we also subtract the SCTP header size.
|
||||||
size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 37 - 8 - 40; // SCTP/DTLS/UDP/IPv6
|
size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 37 - 8 - 40; // SCTP/DTLS/UDP/IPv6
|
||||||
spp.spp_pathmtu = uint32_t(pmtu);
|
spp.spp_pathmtu = to_uint32(pmtu);
|
||||||
PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu;
|
PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,18 +254,28 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
|
|||||||
throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
|
throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
|
||||||
std::to_string(errno));
|
std::to_string(errno));
|
||||||
|
|
||||||
// The default send and receive window size of usrsctp is 256KiB, which is too small for
|
int rcvBuf = 0;
|
||||||
// realistic RTTs, therefore we increase it to at least 1MiB for better performance.
|
socklen_t rcvBufLen = sizeof(rcvBuf);
|
||||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
|
if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen))
|
||||||
const size_t minBufferSize = 1024 * 1024;
|
throw std::runtime_error("Could not get SCTP recv buffer size, errno=" +
|
||||||
|
std::to_string(errno));
|
||||||
|
int sndBuf = 0;
|
||||||
|
socklen_t sndBufLen = sizeof(sndBuf);
|
||||||
|
if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, &sndBufLen))
|
||||||
|
throw std::runtime_error("Could not get SCTP send buffer size, errno=" +
|
||||||
|
std::to_string(errno));
|
||||||
|
|
||||||
// Ensure the buffer is also large enough to accomodate the largest messages
|
// Ensure the buffer is also large enough to accomodate the largest messages
|
||||||
const size_t maxMessageSize = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
|
const size_t maxMessageSize = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
|
||||||
const int bufferSize = int(std::max(minBufferSize, maxMessageSize * 2)); // usrsctp reads as int
|
const int minBuf = int(std::min(maxMessageSize, size_t(std::numeric_limits<int>::max())));
|
||||||
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)))
|
rcvBuf = std::max(rcvBuf, minBuf);
|
||||||
|
sndBuf = std::max(sndBuf, minBuf);
|
||||||
|
|
||||||
|
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, sizeof(rcvBuf)))
|
||||||
throw std::runtime_error("Could not set SCTP recv buffer size, errno=" +
|
throw std::runtime_error("Could not set SCTP recv buffer size, errno=" +
|
||||||
std::to_string(errno));
|
std::to_string(errno));
|
||||||
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)))
|
|
||||||
|
if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, sizeof(sndBuf)))
|
||||||
throw std::runtime_error("Could not set SCTP send buffer size, errno=" +
|
throw std::runtime_error("Could not set SCTP send buffer size, errno=" +
|
||||||
std::to_string(errno));
|
std::to_string(errno));
|
||||||
}
|
}
|
||||||
@ -336,7 +378,7 @@ bool SctpTransport::send(message_ptr message) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
mSendQueue.push(message);
|
mSendQueue.push(message);
|
||||||
updateBufferedAmount(uint16_t(message->stream), long(message_size_func(message)));
|
updateBufferedAmount(to_uint16(message->stream), ptrdiff_t(message_size_func(message)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +395,7 @@ bool SctpTransport::flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SctpTransport::closeStream(unsigned int stream) {
|
void SctpTransport::closeStream(unsigned int stream) {
|
||||||
send(make_message(0, Message::Reset, uint16_t(stream)));
|
send(make_message(0, Message::Reset, to_uint16(stream)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SctpTransport::incoming(message_ptr message) {
|
void SctpTransport::incoming(message_ptr message) {
|
||||||
@ -458,7 +500,7 @@ bool SctpTransport::trySendQueue() {
|
|||||||
if (!trySendMessage(message))
|
if (!trySendMessage(message))
|
||||||
return false;
|
return false;
|
||||||
mSendQueue.pop();
|
mSendQueue.pop();
|
||||||
updateBufferedAmount(uint16_t(message->stream), -long(message_size_func(message)));
|
updateBufferedAmount(to_uint16(message->stream), -ptrdiff_t(message_size_func(message)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -511,12 +553,12 @@ bool SctpTransport::trySendMessage(message_ptr message) {
|
|||||||
case Reliability::Type::Rexmit:
|
case Reliability::Type::Rexmit:
|
||||||
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
||||||
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
|
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
|
||||||
spa.sendv_prinfo.pr_value = uint32_t(std::get<int>(reliability.rexmit));
|
spa.sendv_prinfo.pr_value = to_uint32(std::get<int>(reliability.rexmit));
|
||||||
break;
|
break;
|
||||||
case Reliability::Type::Timed:
|
case Reliability::Type::Timed:
|
||||||
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
||||||
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
|
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
|
||||||
spa.sendv_prinfo.pr_value = uint32_t(std::get<milliseconds>(reliability.rexmit).count());
|
spa.sendv_prinfo.pr_value = to_uint32(std::get<milliseconds>(reliability.rexmit).count());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
|
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
|
||||||
@ -548,10 +590,10 @@ bool SctpTransport::trySendMessage(message_ptr message) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SctpTransport::updateBufferedAmount(uint16_t streamId, long delta) {
|
void SctpTransport::updateBufferedAmount(uint16_t streamId, ptrdiff_t delta) {
|
||||||
// Requires mSendMutex to be locked
|
// Requires mSendMutex to be locked
|
||||||
auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first;
|
auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first;
|
||||||
size_t amount = size_t(std::max(long(it->second) + delta, long(0)));
|
size_t amount = size_t(std::max(ptrdiff_t(it->second) + delta, ptrdiff_t(0)));
|
||||||
if (amount == 0)
|
if (amount == 0)
|
||||||
mBufferedAmount.erase(it);
|
mBufferedAmount.erase(it);
|
||||||
else
|
else
|
||||||
|
@ -39,6 +39,7 @@ namespace rtc::impl {
|
|||||||
class SctpTransport final : public Transport {
|
class SctpTransport final : public Transport {
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
static void SetSettings(const SctpSettings &s);
|
||||||
static void Cleanup();
|
static void Cleanup();
|
||||||
|
|
||||||
using amount_callback = std::function<void(uint16_t streamId, size_t amount)>;
|
using amount_callback = std::function<void(uint16_t streamId, size_t amount)>;
|
||||||
@ -83,7 +84,7 @@ private:
|
|||||||
void doFlush();
|
void doFlush();
|
||||||
bool trySendQueue();
|
bool trySendQueue();
|
||||||
bool trySendMessage(message_ptr message);
|
bool trySendMessage(message_ptr message);
|
||||||
void updateBufferedAmount(uint16_t streamId, long delta);
|
void updateBufferedAmount(uint16_t streamId, ptrdiff_t delta);
|
||||||
void triggerBufferedAmount(uint16_t streamId, size_t amount);
|
void triggerBufferedAmount(uint16_t streamId, size_t amount);
|
||||||
void sendReset(uint16_t streamId);
|
void sendReset(uint16_t streamId);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tcptransport.hpp"
|
#include "tcptransport.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
|
|
||||||
#if RTC_ENABLE_WEBSOCKET
|
#if RTC_ENABLE_WEBSOCKET
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "init.hpp"
|
#include "init.hpp"
|
||||||
|
#include "internals.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "tls.hpp"
|
#include "tls.hpp"
|
||||||
|
|
||||||
|
#include "internals.hpp"
|
||||||
|
|
||||||
#if USE_GNUTLS
|
#if USE_GNUTLS
|
||||||
|
|
||||||
namespace rtc::gnutls {
|
namespace rtc::gnutls {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "track.hpp"
|
#include "track.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "logcounter.hpp"
|
#include "logcounter.hpp"
|
||||||
#include "peerconnection.hpp"
|
#include "peerconnection.hpp"
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define RTC_IMPL_TRANSPORT_H
|
#define RTC_IMPL_TRANSPORT_H
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "internals.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#if RTC_ENABLE_WEBSOCKET
|
#if RTC_ENABLE_WEBSOCKET
|
||||||
|
|
||||||
#include "websocket.hpp"
|
#include "websocket.hpp"
|
||||||
#include "globals.hpp"
|
#include "internals.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "threadpool.hpp"
|
#include "threadpool.hpp"
|
||||||
|
|
||||||
|
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)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "mediachainablehandler.hpp"
|
#include "mediachainablehandler.hpp"
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
MediaChainableHandler::MediaChainableHandler(shared_ptr<MediaHandlerRootElement> root): MediaHandler(), root(root), leaf(root) { }
|
MediaChainableHandler::MediaChainableHandler(shared_ptr<MediaHandlerRootElement> root): MediaHandler(), root(root), leaf(root) { }
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "mediahandlerelement.hpp"
|
#include "mediahandlerelement.hpp"
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
ChainedMessagesProduct make_chained_messages_product() {
|
ChainedMessagesProduct make_chained_messages_product() {
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
@ -1,25 +1,26 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "nalunit.hpp"
|
#include "nalunit.hpp"
|
||||||
#include "globals.hpp"
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel client example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "opusrtppacketizer.hpp"
|
#include "opusrtppacketizer.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
|
OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "impl/certificate.hpp"
|
#include "impl/certificate.hpp"
|
||||||
#include "impl/dtlstransport.hpp"
|
#include "impl/dtlstransport.hpp"
|
||||||
#include "impl/icetransport.hpp"
|
#include "impl/icetransport.hpp"
|
||||||
|
#include "impl/internals.hpp"
|
||||||
#include "impl/peerconnection.hpp"
|
#include "impl/peerconnection.hpp"
|
||||||
#include "impl/processor.hpp"
|
#include "impl/processor.hpp"
|
||||||
#include "impl/sctptransport.hpp"
|
#include "impl/sctptransport.hpp"
|
||||||
@ -266,7 +267,7 @@ shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, DataChan
|
|||||||
void PeerConnection::onDataChannel(
|
void PeerConnection::onDataChannel(
|
||||||
std::function<void(shared_ptr<DataChannel> dataChannel)> callback) {
|
std::function<void(shared_ptr<DataChannel> dataChannel)> callback) {
|
||||||
impl()->dataChannelCallback = callback;
|
impl()->dataChannelCallback = callback;
|
||||||
impl()->triggerDataChannel(); // trigger pending DataChannels
|
impl()->flushPendingDataChannels();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description) {
|
std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description) {
|
||||||
@ -281,7 +282,7 @@ std::shared_ptr<Track> PeerConnection::addTrack(Description::Media description)
|
|||||||
|
|
||||||
void PeerConnection::onTrack(std::function<void(std::shared_ptr<Track>)> callback) {
|
void PeerConnection::onTrack(std::function<void(std::shared_ptr<Track>)> callback) {
|
||||||
impl()->trackCallback = callback;
|
impl()->trackCallback = callback;
|
||||||
impl()->triggerTrack(); // trigger pending tracks
|
impl()->flushPendingTracks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerConnection::onLocalDescription(std::function<void(Description description)> callback) {
|
void PeerConnection::onLocalDescription(std::function<void(Description description)> callback) {
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
/**
|
/**
|
||||||
* libdatachannel streamer example
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "rtcpnackresponder.hpp"
|
#include "rtcpnackresponder.hpp"
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next)
|
RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next)
|
||||||
@ -80,7 +85,7 @@ ChainedIncomingControlProduct RtcpNackResponder::processIncomingControlMessage(m
|
|||||||
if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) {
|
if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fieldsCount = nack->getSeqNoCount();
|
auto fieldsCount = nack->getSeqNoCount();
|
||||||
|
|
||||||
std::vector<uint16_t> missingSequenceNumbers{};
|
std::vector<uint16_t> missingSequenceNumbers{};
|
||||||
|
@ -97,7 +97,7 @@ void RtcpReceivingSession::requestBitrate(unsigned int newBitrate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
|
void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
|
||||||
message_ptr msg = make_message(RTCP_REMB::sizeWithSSRCs(1), Message::Type::Control);
|
message_ptr msg = make_message(RTCP_REMB::SizeWithSSRCs(1), Message::Type::Control);
|
||||||
auto remb = reinterpret_cast<RTCP_REMB *>(msg->data());
|
auto remb = reinterpret_cast<RTCP_REMB *>(msg->data());
|
||||||
remb->preparePacket(mSsrc, 1, bitrate);
|
remb->preparePacket(mSsrc, 1, bitrate);
|
||||||
remb->setSsrc(0, mSsrc);
|
remb->setSsrc(0, mSsrc);
|
||||||
@ -106,7 +106,7 @@ void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) {
|
void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) {
|
||||||
auto msg = make_message(RTCP_RR::sizeWithReportBlocks(1), Message::Type::Control);
|
auto msg = make_message(RTCP_RR::SizeWithReportBlocks(1), Message::Type::Control);
|
||||||
auto rr = reinterpret_cast<RTCP_RR *>(msg->data());
|
auto rr = reinterpret_cast<RTCP_RR *>(msg->data());
|
||||||
rr->preparePacket(mSsrc, 1);
|
rr->preparePacket(mSsrc, 1);
|
||||||
rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS,
|
rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS,
|
||||||
@ -132,7 +132,7 @@ bool RtcpReceivingSession::requestKeyframe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtcpReceivingSession::pushPLI() {
|
void RtcpReceivingSession::pushPLI() {
|
||||||
auto msg = make_message(RTCP_PLI::size(), Message::Type::Control);
|
auto msg = make_message(RTCP_PLI::Size(), Message::Type::Control);
|
||||||
auto *pli = reinterpret_cast<RTCP_PLI *>(msg->data());
|
auto *pli = reinterpret_cast<RTCP_PLI *>(msg->data());
|
||||||
pli->preparePacket(mSsrc);
|
pli->preparePacket(mSsrc);
|
||||||
send(msg);
|
send(msg);
|
||||||
|
@ -1,24 +1,28 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "rtcpsrreporter.hpp"
|
#include "rtcpsrreporter.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) {
|
ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) {
|
||||||
@ -60,8 +64,8 @@ uint64_t RtcpSrReporter::secondsToNTP(double seconds) {
|
|||||||
void RtcpSrReporter::setNeedsToReport() { needsToReport = true; }
|
void RtcpSrReporter::setNeedsToReport() { needsToReport = true; }
|
||||||
|
|
||||||
message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) {
|
message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) {
|
||||||
auto srSize = RTCP_SR::size(0);
|
auto srSize = RTCP_SR::Size(0);
|
||||||
auto msg = make_message(srSize + RTCP_SDES::size({{uint8_t(rtpConfig->cname.size())}}),
|
auto msg = make_message(srSize + RTCP_SDES::Size({{uint8_t(rtpConfig->cname.size())}}),
|
||||||
Message::Type::Control);
|
Message::Type::Control);
|
||||||
auto sr = reinterpret_cast<RTCP_SR *>(msg->data());
|
auto sr = reinterpret_cast<RTCP_SR *>(msg->data());
|
||||||
auto timestamp_s = rtpConfig->timestampToSeconds(timestamp);
|
auto timestamp_s = rtpConfig->timestampToSeconds(timestamp);
|
||||||
|
600
src/rtp.cpp
Normal file
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)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "rtppacketizationconfig.hpp"
|
#include "rtppacketizationconfig.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType,
|
RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType,
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
/*
|
/**
|
||||||
* libdatachannel streamer example
|
|
||||||
* Copyright (c) 2020 Filip Klembara (in2core)
|
* Copyright (c) 2020 Filip Klembara (in2core)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* as published by the Free Software Foundation; either version 2
|
* License as published by the Free Software Foundation; either
|
||||||
* of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* GNU General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* along with this program; If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if RTC_ENABLE_MEDIA
|
#if RTC_ENABLE_MEDIA
|
||||||
|
|
||||||
#include "rtppacketizer.hpp"
|
#include "rtppacketizer.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
RtpPacketizer::RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
|
RtpPacketizer::RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
|
||||||
@ -37,7 +39,7 @@ binary_ptr RtpPacketizer::packetize(shared_ptr<binary> payload, bool setMark) {
|
|||||||
rtp->setMarker(true);
|
rtp->setMarker(true);
|
||||||
}
|
}
|
||||||
rtp->preparePacket();
|
rtp->preparePacket();
|
||||||
memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size());
|
std::memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size());
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "track.hpp"
|
#include "track.hpp"
|
||||||
#include "globals.hpp"
|
|
||||||
|
|
||||||
|
#include "impl/internals.hpp"
|
||||||
#include "impl/track.hpp"
|
#include "impl/track.hpp"
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
@ -46,9 +46,7 @@ bool Track::isOpen(void) const { return impl()->isOpen(); }
|
|||||||
|
|
||||||
bool Track::isClosed(void) const { return impl()->isClosed(); }
|
bool Track::isClosed(void) const { return impl()->isClosed(); }
|
||||||
|
|
||||||
size_t Track::maxMessageSize() const {
|
size_t Track::maxMessageSize() const { return impl()->maxMessageSize(); }
|
||||||
return impl()->maxMessageSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Track::setMediaHandler(shared_ptr<MediaHandler> handler) {
|
void Track::setMediaHandler(shared_ptr<MediaHandler> handler) {
|
||||||
impl()->setMediaHandler(std::move(handler));
|
impl()->setMediaHandler(std::move(handler));
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
#if RTC_ENABLE_WEBSOCKET
|
#if RTC_ENABLE_WEBSOCKET
|
||||||
|
|
||||||
#include "websocket.hpp"
|
#include "websocket.hpp"
|
||||||
#include "globals.hpp"
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
#include "impl/websocket.hpp"
|
#include "impl/websocket.hpp"
|
||||||
|
#include "impl/internals.hpp"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
|
@ -121,12 +121,11 @@ size_t benchmark(milliseconds duration) {
|
|||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cout << "Send failed: " << e.what() << std::endl;
|
std::cout << "Send failed: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When sent data is buffered in the DataChannel,
|
|
||||||
// wait for onBufferedAmountLow callback to continue
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// When sent data is buffered in the DataChannel,
|
||||||
|
// wait for onBufferedAmountLow callback to continue
|
||||||
dc1->onBufferedAmountLow([wdc1 = make_weak_ptr(dc1), &messageData]() {
|
dc1->onBufferedAmountLow([wdc1 = make_weak_ptr(dc1), &messageData]() {
|
||||||
auto dc1 = wdc1.lock();
|
auto dc1 = wdc1.lock();
|
||||||
if (!dc1)
|
if (!dc1)
|
||||||
|
@ -137,11 +137,11 @@ static void RTC_API dataChannelCallback(int pc, int dc, void *ptr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtcSetOpenCallback(dc, openCallback);
|
||||||
rtcSetClosedCallback(dc, closedCallback);
|
rtcSetClosedCallback(dc, closedCallback);
|
||||||
rtcSetMessageCallback(dc, messageCallback);
|
rtcSetMessageCallback(dc, messageCallback);
|
||||||
|
|
||||||
peer->dc = dc;
|
peer->dc = dc;
|
||||||
peer->connected = true;
|
|
||||||
|
|
||||||
const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
|
const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
|
||||||
rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string
|
rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string
|
||||||
|
@ -83,7 +83,7 @@ static void RTC_API closedCallback(int id, void *ptr) {
|
|||||||
static void RTC_API trackCallback(int pc, int tr, void *ptr) {
|
static void RTC_API trackCallback(int pc, int tr, void *ptr) {
|
||||||
Peer *peer = (Peer *)ptr;
|
Peer *peer = (Peer *)ptr;
|
||||||
peer->tr = tr;
|
peer->tr = tr;
|
||||||
peer->connected = true;
|
rtcSetOpenCallback(tr, openCallback);
|
||||||
rtcSetClosedCallback(tr, closedCallback);
|
rtcSetClosedCallback(tr, closedCallback);
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#define CUSTOM_MAX_MESSAGE_SIZE 1048576
|
||||||
|
|
||||||
using namespace rtc;
|
using namespace rtc;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ void test_connectivity() {
|
|||||||
// Custom MTU example
|
// Custom MTU example
|
||||||
config1.mtu = 1500;
|
config1.mtu = 1500;
|
||||||
// Custom max message size
|
// Custom max message size
|
||||||
config1.maxMessageSize = 1048576;
|
config1.maxMessageSize = CUSTOM_MAX_MESSAGE_SIZE;
|
||||||
|
|
||||||
PeerConnection pc1(config1);
|
PeerConnection pc1(config1);
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ void test_connectivity() {
|
|||||||
// Custom MTU example
|
// Custom MTU example
|
||||||
config2.mtu = 1500;
|
config2.mtu = 1500;
|
||||||
// Custom max message size
|
// Custom max message size
|
||||||
config2.maxMessageSize = 1048576;
|
config2.maxMessageSize = CUSTOM_MAX_MESSAGE_SIZE;
|
||||||
// Port range example
|
// Port range example
|
||||||
config2.portRangeBegin = 5000;
|
config2.portRangeBegin = 5000;
|
||||||
config2.portRangeEnd = 6000;
|
config2.portRangeEnd = 6000;
|
||||||
@ -105,26 +107,29 @@ void test_connectivity() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dc->onOpen([wdc = make_weak_ptr(dc)]() {
|
||||||
|
if (auto dc = wdc.lock())
|
||||||
|
dc->send("Hello from 2");
|
||||||
|
});
|
||||||
|
|
||||||
dc->onMessage([](variant<binary, string> message) {
|
dc->onMessage([](variant<binary, string> message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Message 2: " << get<string>(message) << endl;
|
cout << "Message 2: " << get<string>(message) << endl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dc->send("Hello from 2");
|
|
||||||
|
|
||||||
std::atomic_store(&dc2, dc);
|
std::atomic_store(&dc2, dc);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto dc1 = pc1.createDataChannel("test");
|
auto dc1 = pc1.createDataChannel("test");
|
||||||
dc1->onOpen([wdc1 = make_weak_ptr(dc1)]() {
|
|
||||||
auto dc1 = wdc1.lock();
|
|
||||||
if (!dc1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cout << "DataChannel 1: Open" << endl;
|
dc1->onOpen([wdc1 = make_weak_ptr(dc1)]() {
|
||||||
dc1->send("Hello from 1");
|
if (auto dc1 = wdc1.lock()) {
|
||||||
|
cout << "DataChannel 1: Open" << endl;
|
||||||
|
dc1->send("Hello from 1");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dc1->onMessage([](const variant<binary, string> &message) {
|
dc1->onMessage([](const variant<binary, string> &message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Message 1: " << get<string>(message) << endl;
|
cout << "Message 1: " << get<string>(message) << endl;
|
||||||
@ -144,7 +149,7 @@ void test_connectivity() {
|
|||||||
if (!adc2 || !adc2->isOpen() || !dc1->isOpen())
|
if (!adc2 || !adc2->isOpen() || !dc1->isOpen())
|
||||||
throw runtime_error("DataChannel is not open");
|
throw runtime_error("DataChannel is not open");
|
||||||
|
|
||||||
if (dc1->maxMessageSize() != 1048576 || dc2->maxMessageSize() != 1048576)
|
if (dc1->maxMessageSize() != CUSTOM_MAX_MESSAGE_SIZE || dc2->maxMessageSize() != CUSTOM_MAX_MESSAGE_SIZE)
|
||||||
throw runtime_error("DataChannel max message size is incorrect");
|
throw runtime_error("DataChannel max message size is incorrect");
|
||||||
|
|
||||||
if (auto addr = pc1.localAddress())
|
if (auto addr = pc1.localAddress())
|
||||||
@ -175,25 +180,26 @@ void test_connectivity() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dc->onOpen([wdc = make_weak_ptr(dc)]() {
|
||||||
|
if (auto dc = wdc.lock())
|
||||||
|
dc->send("Second hello from 2");
|
||||||
|
});
|
||||||
|
|
||||||
dc->onMessage([](variant<binary, string> message) {
|
dc->onMessage([](variant<binary, string> message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Second Message 2: " << get<string>(message) << endl;
|
cout << "Second Message 2: " << get<string>(message) << endl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dc->send("Send hello from 2");
|
|
||||||
|
|
||||||
std::atomic_store(&second2, dc);
|
std::atomic_store(&second2, dc);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto second1 = pc1.createDataChannel("second");
|
auto second1 = pc1.createDataChannel("second");
|
||||||
second1->onOpen([wsecond1 = make_weak_ptr(dc1)]() {
|
second1->onOpen([wsecond1 = make_weak_ptr(dc1)]() {
|
||||||
auto second1 = wsecond1.lock();
|
if (auto second1 = wsecond1.lock()) {
|
||||||
if (!second1)
|
cout << "Second DataChannel 1: Open" << endl;
|
||||||
return;
|
second1->send("Second hello from 1");
|
||||||
|
}
|
||||||
cout << "Second DataChannel 1: Open" << endl;
|
|
||||||
second1->send("Second hello from 1");
|
|
||||||
});
|
});
|
||||||
dc1->onMessage([](const variant<binary, string> &message) {
|
dc1->onMessage([](const variant<binary, string> &message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
|
@ -108,14 +108,17 @@ void test_turn_connectivity() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dc->onOpen([wdc = make_weak_ptr(dc)]() {
|
||||||
|
if (auto dc = wdc.lock())
|
||||||
|
dc->send("Hello from 2");
|
||||||
|
});
|
||||||
|
|
||||||
dc->onMessage([](variant<binary, string> message) {
|
dc->onMessage([](variant<binary, string> message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Message 2: " << get<string>(message) << endl;
|
cout << "Message 2: " << get<string>(message) << endl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dc->send("Hello from 2");
|
|
||||||
|
|
||||||
std::atomic_store(&dc2, dc);
|
std::atomic_store(&dc2, dc);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -175,14 +178,17 @@ void test_turn_connectivity() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dc->onOpen([wdc = make_weak_ptr(dc)]() {
|
||||||
|
if (auto dc = wdc.lock())
|
||||||
|
dc->send("Second hello from 2");
|
||||||
|
});
|
||||||
|
|
||||||
dc->onMessage([](variant<binary, string> message) {
|
dc->onMessage([](variant<binary, string> message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Second Message 2: " << get<string>(message) << endl;
|
cout << "Second Message 2: " << get<string>(message) << endl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dc->send("Send hello from 2");
|
|
||||||
|
|
||||||
std::atomic_store(&second2, dc);
|
std::atomic_store(&second2, dc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user