Merge branch 'example_improvements'
# Conflicts: # CMakeLists.txt # src/formats/h264.hh # src/formats/h265.hh # src/formats/h266.hh # src/formats/h26x.cc # src/formats/h26x.hh # src/lib.cc # src/pkt_dispatch.hh # src/rtp.cc # uvgRTP.pro
This commit is contained in:
commit
f62ade9c70
|
@ -1,12 +1,15 @@
|
|||
# Simple CircleCI configuration for building uvgRTP
|
||||
# ToDo: add tests
|
||||
|
||||
|
||||
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: cimg/base:2021.04
|
||||
resource_class: small
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
|
@ -20,8 +23,74 @@ jobs:
|
|||
command: 'cmake -H. -Bbuild'
|
||||
- run:
|
||||
name: Build the uvgRTP library
|
||||
command: 'cmake --build build -j'
|
||||
command: 'cmake --build build'
|
||||
- run:
|
||||
name: Build test application
|
||||
# ToDo: add -lcrypto++
|
||||
command: 'mkdir include/uvgrtp && cp -rf include/*.hh include/uvgrtp/ && g++ -D__RTP_NO_CRYPTO__ docs/examples/configuration.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_configuration'
|
||||
name: Build binding example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/binding.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_binding'
|
||||
- run:
|
||||
name: Run binding example
|
||||
command: './example_binding'
|
||||
- run:
|
||||
name: Build configuration example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/configuration.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_configuration'
|
||||
- run:
|
||||
name: Run configuration example
|
||||
command: './example_configuration'
|
||||
- run:
|
||||
name: Build timestamp example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/custom_timestamps.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_timestamp'
|
||||
- run:
|
||||
name: Run timestamp example
|
||||
command: './example_timestamp'
|
||||
- run:
|
||||
name: Build hook receiving example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/receiving_hook.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_hook'
|
||||
- run:
|
||||
name: Run RTP hook example
|
||||
command: './example_hook'
|
||||
- run:
|
||||
name: Build poll receiving example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/receiving_poll.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_poll'
|
||||
- run:
|
||||
name: Run RTP polling example
|
||||
command: './example_poll'
|
||||
- run:
|
||||
name: Build RTCP example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/rtcp_hook.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_rtcp'
|
||||
- run:
|
||||
name: Run RTCP hook example
|
||||
command: './example_rtcp'
|
||||
- run:
|
||||
name: Build sending example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/sending.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_sending'
|
||||
- run:
|
||||
name: Run sending example
|
||||
command: './example_sending'
|
||||
- run:
|
||||
name: Build generic example
|
||||
command: 'g++ -D__RTP_NO_CRYPTO__ docs/examples/sending_generic.cc -Iinclude/ build/libuvgrtp.a -lpthread -o example_generic'
|
||||
- run:
|
||||
name: Run generic format example
|
||||
command: './example_generic'
|
||||
- run:
|
||||
name: Install Crypto++
|
||||
command: 'sudo apt-get install -y libcrypto++-dev'
|
||||
- run:
|
||||
name: Create build files for crypto++ build
|
||||
command: 'cmake -H. -Bbuild_c'
|
||||
- run:
|
||||
name: Build the uvgRTP library with Crypto++ enabled
|
||||
command: 'cmake --build build_c'
|
||||
- run:
|
||||
name: Build user managed SRTP key example
|
||||
command: 'g++ docs/examples/srtp_user.cc -Iinclude/ build_c/libuvgrtp.a -lpthread -lcryptopp -o example_srtp'
|
||||
- run:
|
||||
name: Run user managed SRTP key example
|
||||
command: './example_srtp'
|
||||
- run:
|
||||
name: Build ZRTP + SRTP multistream example
|
||||
command: 'g++ docs/examples/zrtp_multistream.cc -Iinclude/ build_c/libuvgrtp.a -lpthread -lcryptopp -o example_zrtp'
|
||||
- run:
|
||||
name: Run ZRTP + SRTP multistream key example
|
||||
command: './example_zrtp'
|
||||
|
||||
|
|
|
@ -109,17 +109,17 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
src/srtp/srtp.hh
|
||||
src/srtp/srtcp.hh
|
||||
|
||||
include/util.hh
|
||||
include/clock.hh
|
||||
include/crypto.hh
|
||||
include/debug.hh
|
||||
include/frame.hh
|
||||
include/lib.hh
|
||||
include/media_stream.hh
|
||||
include/rtcp.hh
|
||||
include/runner.hh
|
||||
include/session.hh
|
||||
include/socket.hh
|
||||
include/uvgrtp/util.hh
|
||||
include/uvgrtp/clock.hh
|
||||
include/uvgrtp/crypto.hh
|
||||
include/uvgrtp/debug.hh
|
||||
include/uvgrtp/frame.hh
|
||||
include/uvgrtp/lib.hh
|
||||
include/uvgrtp/media_stream.hh
|
||||
include/uvgrtp/rtcp.hh
|
||||
include/uvgrtp/runner.hh
|
||||
include/uvgrtp/session.hh
|
||||
include/uvgrtp/socket.hh
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
@ -212,7 +212,7 @@ install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_version EXPORT ${PROJECT_NAME}Ta
|
|||
COMPONENT ${PROJECT_NAME}_Runtime)
|
||||
|
||||
#Copy all header files to the <prefix>/include/uvgrtp directory
|
||||
file(GLOB DEPLOY_FILES_AND_DIRS "${CMAKE_SOURCE_DIR}/include/*")
|
||||
file(GLOB DEPLOY_FILES_AND_DIRS "${CMAKE_SOURCE_DIR}/include/uvgrtp/*")
|
||||
install(FILES ${DEPLOY_FILES_AND_DIRS}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/
|
||||
COMPONENT ${PROJECT_NAME}_Develop)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "version.hh"
|
||||
#include "uvgrtp/version.hh"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
release/*
|
||||
debug/*
|
|
@ -1,54 +1,134 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
|
||||
#define PAYLOAD_MAXLEN 256
|
||||
#include <iostream>
|
||||
|
||||
void hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
/* Some NATs may close the hole created in the firewall if the stream is not bidirectional,
|
||||
* i.e., only one participant produces and the other consumes.
|
||||
*
|
||||
* To prevent the connection from closing, uvgRTP can be instructed to keep the hole open
|
||||
* by periodically sending 1-byte datagram to remote (once every 2 seconds).
|
||||
*
|
||||
* All RFC 3550 compatible implementations should ignore the packet as it is not recognized
|
||||
* to be a valid RTP frame and the stream should work without problems.
|
||||
*
|
||||
* This feature is enabled by giving RCE_HOLEPUNCH_KEEPALIVE flag to the unidirectional
|
||||
* media_stream that acts as the receiver. Please note that this flag is only necessary
|
||||
* if you're using the created media_stream object as a unidirectional stream and you are
|
||||
* noticing that after a while the packets are no longer passing through the firewall
|
||||
|
||||
* In this example, we demonstrate the functionality of RCE_HOLEPUNCH_KEEPALIVE by sending
|
||||
* a dummy stream from sender to receiver with hole punching feature enabled by configuration
|
||||
* flag of the receiver.
|
||||
*/
|
||||
|
||||
// network parameters of the example
|
||||
constexpr char LOCAL_INTERFACE[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
// Parameters of sent dummy frames
|
||||
constexpr uint16_t PAYLOAD_LEN = 256; // how large are test packets
|
||||
constexpr int AMOUNT_OF_PACKETS = 100; // how many
|
||||
constexpr int PACKET_INTERVAL_MS = 1000/30; // how often
|
||||
|
||||
// Function where received frames are processed
|
||||
void frame_process_hook(void *arg, uvgrtp::frame::rtp_frame *frame);
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, int frame_index);
|
||||
void cleanup(uvgrtp::context& rtp_ctx,
|
||||
uvgrtp::session *sending_session, uvgrtp::session *receiving_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *recv);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
std::cout << "Starting uvgRTP binding example" << std::endl;
|
||||
|
||||
uvgrtp::context rtp_ctx;
|
||||
uvgrtp::session *sending_session = rtp_ctx.create_session(LOCAL_INTERFACE, REMOTE_ADDRESS);
|
||||
uvgrtp::media_stream *send = sending_session->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_H265, RCE_NO_FLAGS);
|
||||
|
||||
/* Start session with remote at IP address 10.21.25.2
|
||||
* and bind ourselves to interface pointed to by the IP address 10.21.25.200 */
|
||||
uvgrtp::session *s1 = rtp_ctx.create_session("10.21.25.2", "10.21.25.200");
|
||||
/* RCE flags or RTP Context Enable flags are given when creating the Media Stream.
|
||||
Notice the RCE_HOLEPUNCH_KEEPALIVE flag which keeps the NAT/firewall open */
|
||||
int flags = RCE_HOLEPUNCH_KEEPALIVE;
|
||||
uvgrtp::session *receiving_session = rtp_ctx.create_session(REMOTE_ADDRESS, LOCAL_INTERFACE);
|
||||
uvgrtp::media_stream *recv = receiving_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_H265, flags);
|
||||
|
||||
/* 8888 is source port or the port for the interface where data is received (ie. 10.21.25.200:8888)
|
||||
* 8889 is remote port or the port for the interface where the data is sent (ie. 10.21.25.2:8889) */
|
||||
uvgrtp::media_stream *send = s1->create_stream(8888, 8889, RTP_FORMAT_H265, RTP_NO_FLAGS);
|
||||
|
||||
/* Some NATs may close the hole created in the firewall if the stream is not bidirectional,
|
||||
* i.e., only one participant produces and the other consumes.
|
||||
*
|
||||
* To prevent the connection from closing, uvgRTP can be instructed to keep the hole open
|
||||
* by periodically sending 1-byte datagram to remote (once every 2 seconds).
|
||||
*
|
||||
* This is done by giving RCE_HOLEPUNCH_KEEPALIVE to the unidirectional media_stream that
|
||||
* acts as the receiver
|
||||
*
|
||||
* All RFC 3550 compatible implementations should ignore the packet as it is not recognized
|
||||
* to be a valid RTP frame and the stream should work without problems.
|
||||
*
|
||||
* NOTE: this flag is only necessary if you're using the created media_stream object
|
||||
* as a unidirectional stream and you are noticing that after a while the packets are no longer
|
||||
* passing through the firewall */
|
||||
uvgrtp::media_stream *recv = s1->create_stream(7777, 6666, RTP_FORMAT_H265, RCE_HOLEPUNCH_KEEPALIVE);
|
||||
|
||||
/* install receive hook for asynchronous reception */
|
||||
recv->install_receive_hook(nullptr, hook);
|
||||
|
||||
while (true) {
|
||||
std::unique_ptr<uint8_t[]> buffer = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_MAXLEN]);
|
||||
|
||||
if (send->push_frame(std::move(buffer), PAYLOAD_MAXLEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "failed to push hevc frame\n");
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(800));
|
||||
// install receive hook for asynchronous reception
|
||||
if (!recv || recv->install_receive_hook(nullptr, frame_process_hook) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to install receive hook!" << std::endl;
|
||||
cleanup(rtp_ctx, sending_session, receiving_session, send, recv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rtp_ctx.destroy_session(s1);
|
||||
rtp_ctx.destroy_session(s2);
|
||||
if (send)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < AMOUNT_OF_PACKETS; ++i)
|
||||
{
|
||||
std::cout << "Sending frame " << i + 1 << '/' << AMOUNT_OF_PACKETS << std::endl;
|
||||
|
||||
std::unique_ptr<uint8_t[]> dummy_frame =
|
||||
std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
|
||||
|
||||
if (send->push_frame(std::move(dummy_frame), PAYLOAD_LEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to send frame" << std::endl;
|
||||
cleanup(rtp_ctx, sending_session, receiving_session, send, recv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Send frames at constant intervals. This example makes sure the frames are
|
||||
* sent exactly at the right time by calculating the timeslots for each frame.
|
||||
* If the full data is already available in real life, you can send it as fast
|
||||
* as your network can handle, but here we simulate how a 30 fps camera would
|
||||
* send frames. */
|
||||
wait_until_next_frame(start, i);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(rtp_ctx, sending_session, receiving_session, send, recv);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void frame_process_hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
std::cout << "Received frame. Payload size: " << frame->payload_len << std::endl;
|
||||
|
||||
/* Use the hook function for handing over the frame to other thread.
|
||||
* It is not recommended to perform heavy computation in hook function
|
||||
* as this may interfere with uvgRTP:s ability to receive frames. */
|
||||
|
||||
uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point &start, int frame_index)
|
||||
{
|
||||
// wait until it is time to send the next frame. Simulates a steady sending pace
|
||||
// and included only for demostration purposes since you can use uvgRTP to send
|
||||
// packets as fast as desired
|
||||
auto time_since_start = std::chrono::steady_clock::now() - start;
|
||||
auto next_frame_time = (frame_index + 1)*std::chrono::milliseconds(PACKET_INTERVAL_MS);
|
||||
if (next_frame_time > time_since_start)
|
||||
{
|
||||
std::this_thread::sleep_for(next_frame_time - time_since_start);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context &rtp_ctx,
|
||||
uvgrtp::session *sending_session, uvgrtp::session *receiving_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *recv)
|
||||
{
|
||||
if (send)
|
||||
sending_session->destroy_stream(send);
|
||||
if (recv)
|
||||
receiving_session->destroy_stream(recv);
|
||||
|
||||
if (sending_session)
|
||||
rtp_ctx.destroy_session(sending_session);
|
||||
if (receiving_session)
|
||||
rtp_ctx.destroy_session(receiving_session);
|
||||
}
|
||||
|
|
|
@ -1,45 +1,143 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
|
||||
#define PAYLOAD_MAXLEN 4096
|
||||
#include <iostream>
|
||||
|
||||
/* This example demonstrates using the configuration options of uvgRTP.
|
||||
* There are three types of configuration flags: RCE, RCC and RTP flags
|
||||
* RCE (RTP Context Enable) flags are used to enable different features
|
||||
* of uvgRTP and are passed when a new media_stream is created.
|
||||
*
|
||||
* RCC (RTP Context Configuration) flags can be used to modify the behavior of media
|
||||
* stream. They are used by calling configure_ctx-function of media_stream
|
||||
* and using the flag and value as parameters.
|
||||
*
|
||||
* Lastly, RTP flags can be added to modify the sending process of uvgRTP.
|
||||
*/
|
||||
|
||||
|
||||
/* This example implements one sender and one receiver.
|
||||
* These are their used interfaces and ports. You may
|
||||
* edit these if you wish to test this example on different machines */
|
||||
constexpr char LOCAL_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
|
||||
// parameters for this example
|
||||
constexpr int BUFFER_SIZE_MB = 40 * 1000 * 1000;
|
||||
constexpr int MAX_PACKET_INTERVAL_MS = 150;
|
||||
|
||||
constexpr size_t PAYLOAD_LEN = 4096;
|
||||
constexpr int SEND_TEST_PACKETS = 1000;
|
||||
|
||||
void receive_process_hook(void *arg, uvgrtp::frame::rtp_frame *frame);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive);
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
std::cout << "Starting uvgRTP configuration example" << std::endl;
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
|
||||
/* Some of the functionality of uvgRTP can be enabled/disabled using RCE_* flags.
|
||||
/* Some of the functionality of uvgRTP can be enabled or disabled using RCE_* flags.
|
||||
*
|
||||
* For example, here the created MediaStream object has RTCP enabled,
|
||||
* does not utilize system call clustering to reduce the possibility of packet dropping
|
||||
* and prepends a 4-byte HEVC start code (0x00000001) before each NAL unit */
|
||||
unsigned flags =
|
||||
* does not utilize system call clustering to reduce the possibility of packet dropping */
|
||||
int send_flags =
|
||||
RCE_RTCP | /* enable RTCP */
|
||||
RCE_NO_SYSTEM_CALL_CLUSTERING; /* disable system call clustering */
|
||||
|
||||
/* Prepends a 4-byte HEVC start code (0x00000001) before each NAL unit.
|
||||
* This way the stream can be saved into a file and played by a media player */
|
||||
int receive_flags =
|
||||
RCE_RTCP | /* enable RTCP */
|
||||
RCE_NO_SYSTEM_CALL_CLUSTERING | /* disable system call clustering */
|
||||
RCE_H26X_PREPEND_SC; /* prepend a start code before each NAL unit */
|
||||
|
||||
uvgrtp::media_stream *hevc = sess->create_stream(8888, 8889, RTP_FORMAT_H265, flags);
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *local_session = ctx.create_session(REMOTE_ADDRESS);
|
||||
uvgrtp::media_stream *send = local_session->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_H265, send_flags);
|
||||
|
||||
/* uvgRTP context can also be configured using RCC_* flags
|
||||
* These flags do not enable/disable functionality but alter default behaviour of uvgRTP
|
||||
*
|
||||
* For example, here UDP send/recv buffers are increased to 40MB
|
||||
* and frame delay is set 150 milliseconds to allow frames to arrive a little late */
|
||||
hevc->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 40 * 1000 * 1000);
|
||||
hevc->configure_ctx(RCC_UDP_SND_BUF_SIZE, 40 * 1000 * 1000);
|
||||
hevc->configure_ctx(RCC_PKT_MAX_DELAY, 150);
|
||||
uvgrtp::session *remote_session = ctx.create_session(LOCAL_ADDRESS);
|
||||
uvgrtp::media_stream *receive = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT, RTP_FORMAT_H265, receive_flags);
|
||||
|
||||
for (;;) {
|
||||
auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_MAXLEN]);
|
||||
if (receive)
|
||||
{
|
||||
/* uvgRTP context can also be configured using RCC_* flags
|
||||
* These flags do not enable/disable functionality but alter default behaviour of uvgRTP
|
||||
*
|
||||
* For example, here UDP receive buffer is increased to BUFFER_SIZE_MB
|
||||
* and frame delay is set PACKET_MAX_DELAY_MS to allow frames to arrive a little late */
|
||||
receive->configure_ctx(RCC_UDP_RCV_BUF_SIZE, BUFFER_SIZE_MB);
|
||||
receive->configure_ctx(RCC_PKT_MAX_DELAY, MAX_PACKET_INTERVAL_MS);
|
||||
|
||||
if (hevc->push_frame(std::move(buffer), PAYLOAD_MAXLEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "Failed to send RTP frame!");
|
||||
// install receive hook for asynchronous reception
|
||||
receive->install_receive_hook(nullptr, receive_process_hook);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to install receive hook!" << std::endl;
|
||||
cleanup(ctx, local_session, remote_session, send, receive);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
if (send)
|
||||
{
|
||||
|
||||
return 0;
|
||||
/* Here, the UDP send buffer is increased to BUFFER_SIZE_MB */
|
||||
send->configure_ctx(RCC_UDP_SND_BUF_SIZE, BUFFER_SIZE_MB);
|
||||
|
||||
for (int i = 0; i < SEND_TEST_PACKETS; ++i)
|
||||
{
|
||||
auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
|
||||
|
||||
if ((i+1)%10 == 0 || i == 0) // print every 10 frames and first
|
||||
std::cout << "Sending frame " << i + 1 << '/' << SEND_TEST_PACKETS << std::endl;
|
||||
|
||||
if (send->push_frame(std::move(buffer), PAYLOAD_LEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to send RTP frame!" << std::endl;
|
||||
cleanup(ctx, local_session, remote_session, send, receive);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(ctx, local_session, remote_session, send, receive);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void receive_process_hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
std::cout << "Received frame. Payload size: " << frame->payload_len << std::endl;
|
||||
uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context &ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive)
|
||||
{
|
||||
if (send)
|
||||
{
|
||||
local_session->destroy_stream(send);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
{
|
||||
remote_session->destroy_stream(receive);
|
||||
}
|
||||
|
||||
if (local_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(local_session);
|
||||
}
|
||||
|
||||
if (remote_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(remote_session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +1,132 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
|
||||
#define PAYLOAD_MAXLEN 100
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
/* This example demostrates the usage of custom timestamps. Often when
|
||||
* streaming multiple media, there are different lengths steps in in the
|
||||
* processing flow. Setting the timestamps manually instead of using uvgRTPs
|
||||
* internal timestamp system eliminates the timestamp offset.
|
||||
*
|
||||
* As a concrete example, audio encoding is usually faster than video encoding and
|
||||
* this can cause small offset between video and audio even before reaching uvgRTP.
|
||||
* This can be mitigated by capturing the timestamp at the time of recording video/audio
|
||||
* and using that as the custom timestamp. This is also how RFC 3550 (RTP) recommends
|
||||
* going about this. */
|
||||
|
||||
// set these as you want. Take care that the RTCP is set as RTP port +1
|
||||
constexpr char LOCAL_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
// RTP clock for video increments 90000 in RTP payload format RFC
|
||||
constexpr uint32_t VIDEO_CLOCK_RATE = 90000;
|
||||
constexpr uint32_t VIDEO_FRAME_RATE = 30;
|
||||
|
||||
constexpr size_t PAYLOAD_LEN = 100;
|
||||
constexpr int SEND_TEST_PACKETS = 500;
|
||||
|
||||
void process_received_frame_hook(void *arg, uvgrtp::frame::rtp_frame *frame);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* To use the library, one must create a global RTP context object */
|
||||
std::cout << "Starting uvgRTP custom timestamp example" << std::endl;
|
||||
|
||||
uvgrtp::context ctx;
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
int flags = RCE_RTCP; // enable RTCP
|
||||
uvgrtp::session *local_session = ctx.create_session(REMOTE_ADDRESS);
|
||||
uvgrtp::media_stream *send = local_session->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_H265, flags);
|
||||
|
||||
/* Create MediaStream and enable RTCP for the stream */
|
||||
uvgrtp::media_stream *hevc = sess->create_stream(8888, 8889, RTP_FORMAT_H265, RCE_RTCP);
|
||||
uvgrtp::session *remote_session = ctx.create_session(LOCAL_ADDRESS);
|
||||
uvgrtp::media_stream *receive = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_H265, flags);
|
||||
|
||||
uint8_t *buffer = new uint8_t[PAYLOAD_MAXLEN];
|
||||
uint32_t clock_rate = 90000 / 30;
|
||||
uint32_t timestamp = 0;
|
||||
|
||||
/* If you don't want uvgRTP to handle timestamping but wish to do that yourself
|
||||
* AND you want to use RTCP, timestamping info must be provided for the RTCP so
|
||||
* it is able calculate sensible values for synchronization info
|
||||
*
|
||||
* The first parameter is NTP time associated with the corresponding RTP timestamp,
|
||||
* second parameter is clock rate and the third parameter is RTP timestamp for t = 0
|
||||
* (it can be zero or some random number, does not matter) */
|
||||
hevc->get_rtcp()->set_ts_info(uvgrtp::clock::ntp::now(), clock_rate, timestamp);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
/* The timestamp is given as the third parameter and it should be advanced
|
||||
* in accordance with the media stream clock rate. For example, for HEVC, the clock rate is 90000. */
|
||||
if (hevc->push_frame(buffer, PAYLOAD_MAXLEN, clock_rate * timestamp++, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "Failed to send RTP frame!");
|
||||
if (receive)
|
||||
{
|
||||
/* install receive hook for asynchronous reception */
|
||||
if (receive->install_receive_hook(nullptr, process_received_frame_hook) != RTP_OK)
|
||||
{
|
||||
cleanup(ctx, local_session, remote_session, send, receive);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
delete[] buffer;
|
||||
ctx.destroy_session(sess);
|
||||
if (send)
|
||||
{
|
||||
// RTP specification says there should be a random initial offset
|
||||
srand (time(NULL));
|
||||
uint32_t start_timestamp = rand()%UINT32_MAX;
|
||||
|
||||
return 0;
|
||||
/* If you don't want uvgRTP to handle timestamping but wish to do that yourself
|
||||
* AND you want to use RTCP, timestamping info must be provided for the RTCP so
|
||||
* it is able calculate sensible values for synchronization info
|
||||
*
|
||||
* The first parameter is NTP time associated with the corresponding RTP timestamp,
|
||||
* second parameter is clock rate and the third parameter is RTP timestamp for t = 0
|
||||
* (it can be zero or some random number, does not matter) */
|
||||
send->get_rtcp()->set_ts_info(uvgrtp::clock::ntp::now(), VIDEO_CLOCK_RATE, start_timestamp);
|
||||
|
||||
for (int i = 0; i < SEND_TEST_PACKETS; ++i)
|
||||
{
|
||||
auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
|
||||
|
||||
// fake timestamp. This way the receiver can play the frames at a lower pace, even if
|
||||
// we generate them really fast.
|
||||
uint32_t timestamp = start_timestamp + i*VIDEO_CLOCK_RATE/VIDEO_FRAME_RATE;
|
||||
|
||||
std::cout << "Sending frame " << i + 1 << '/' << SEND_TEST_PACKETS <<
|
||||
" with timestamp: " << timestamp << std::endl;
|
||||
|
||||
/* The timestamp is given as the third parameter and it should be advanced
|
||||
* in accordance with the media stream clock rate. For example, for HEVC, the clock rate is 90000. */
|
||||
if (send->push_frame(std::move(buffer), PAYLOAD_LEN, timestamp, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to send RTP frame!";
|
||||
cleanup(ctx, local_session, remote_session, send, receive);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(ctx, local_session, remote_session, send, receive);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void process_received_frame_hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
std::cout << "Received frame. Timestamp: " << frame->header.timestamp << std::endl;
|
||||
uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context &ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive)
|
||||
{
|
||||
if (send)
|
||||
{
|
||||
local_session->destroy_stream(send);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
{
|
||||
remote_session->destroy_stream(receive);
|
||||
}
|
||||
|
||||
if (local_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(local_session);
|
||||
}
|
||||
|
||||
if (remote_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(remote_session);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
#include <uvgrtp/formats/rawvideo.hh>
|
||||
|
||||
#define PAYLOAD_MAXLEN 4096
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uvgrtp::context ctx;
|
||||
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
uvgrtp::media_stream *rwv = sess->create_stream(8888, 8889, RTP_FORMAT_RAW_VIDEO, RTP_NO_FLAGS);
|
||||
|
||||
uvgrtp::formats::rwv_config conf = {
|
||||
.pixfmt = uvgrtp::formats::RWV_FMT_YUV420,
|
||||
.progressive = false, /* progressive */
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.depth = 8 /* bit depth */
|
||||
};
|
||||
|
||||
rwv->configure_ctx(&conf);
|
||||
|
||||
for (;;) {
|
||||
auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_MAXLEN]);
|
||||
|
||||
if (rwv->push_frame(std::move(buffer), PAYLOAD_MAXLEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "Failed to send RTP frame!");
|
||||
}
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,27 +1,47 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
|
||||
#include <thread>
|
||||
|
||||
void receive_hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
/* Now we own the frame. Here you could give the frame to the application
|
||||
* if f.ex "arg" was some application-specific pointer
|
||||
*
|
||||
* arg->copy_frame(frame) or whatever
|
||||
*
|
||||
* When we're done with the frame, it must be deallocated manually */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
/* There are two main ways of getting received RTP frames from uvgRTP.
|
||||
* This example demonstrates the usage of hook function to receive RTP frames.
|
||||
*
|
||||
* The advantage of using a hook function is minimal CPU usage and delay between
|
||||
* uvgRTP receiving the frame and application processing the frame. When using
|
||||
* the hook method, the application must take care that it is not using the hook
|
||||
* function for heavy processing since this may block RTP frame reception.
|
||||
*
|
||||
* Hook based frame reception is generally recommended for most serious applications,
|
||||
* but there can be situations where polling method is better, especially if performance
|
||||
* is not a huge concern or if there needs to be tight control when the frame is
|
||||
* received by the application.
|
||||
*
|
||||
* This example only implements the receiving, but it can be used together with the
|
||||
* sending example to test the functionality.
|
||||
*/
|
||||
|
||||
// parameters for this test. You can change these to suit your network environment
|
||||
constexpr uint16_t LOCAL_PORT = 8890;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8888;
|
||||
|
||||
// This example runs for 5 seconds
|
||||
constexpr auto RECEIVE_TIME_S = std::chrono::seconds(3);
|
||||
|
||||
void rtp_receive_hook(void *arg, uvgrtp::frame::rtp_frame *frame);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session *sess, uvgrtp::media_stream *receiver);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
std::cout << "Starting uvgRTP RTP receive hook example" << std::endl;
|
||||
|
||||
uvgrtp::context ctx;
|
||||
/* There remote address and port are needed if the .
|
||||
uvgRTP API is */
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::media_stream *hevc = sess->create_stream(8888, 8889, RTP_FORMAT_H265, 0);
|
||||
uvgrtp::session *sess = ctx.create_session(REMOTE_ADDRESS);
|
||||
int flags = RTP_NO_FLAGS;
|
||||
uvgrtp::media_stream *receiver = sess->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_H265, flags);
|
||||
|
||||
/* Receive hook can be installed and uvgRTP will call this hook when an RTP frame is received
|
||||
*
|
||||
|
@ -32,10 +52,45 @@ int main(void)
|
|||
* specfic object if the application needs to be called inside the hook
|
||||
*
|
||||
* If it's not needed, it should be set to nullptr */
|
||||
hevc->install_receive_hook(nullptr, receive_hook);
|
||||
if (!receiver || receiver->install_receive_hook(nullptr, rtp_receive_hook) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to install RTP reception hook";
|
||||
cleanup(ctx, sess, receiver);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
std::cout << "Waiting incoming packets for " << RECEIVE_TIME_S.count() << " s" << std::endl;
|
||||
|
||||
return 0;
|
||||
std::this_thread::sleep_for(RECEIVE_TIME_S); // lets this example run for some time
|
||||
|
||||
cleanup(ctx, sess, receiver);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void rtp_receive_hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
std::cout << "Received RTP frame" << std::endl;
|
||||
|
||||
/* Now we own the frame. Here you could give the frame to the application
|
||||
* if f.ex "arg" was some application-specific pointer
|
||||
*
|
||||
* arg->copy_frame(frame) or whatever
|
||||
*
|
||||
* When we're done with the frame, it must be deallocated manually */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session *sess, uvgrtp::media_stream *receiver)
|
||||
{
|
||||
if (receiver)
|
||||
{
|
||||
sess->destroy_stream(receiver);
|
||||
}
|
||||
|
||||
if (sess)
|
||||
{
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,85 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
|
||||
/* This example demostrates using polling to receive RTP frames. Polling in
|
||||
* uvgRTP can be done with function pull_frame in media_streamer. This pull_frame
|
||||
* function can be used with or without a timeout argument. If used without a timeout
|
||||
* argument, the function will return when a frame is received or the media stream
|
||||
* is destroyed. At this point I would recommend using it with timeout and not
|
||||
* destroying the media stream since this functionality has not been verified.
|
||||
*
|
||||
* Compared to hook function, polling offers more control on frame reception,
|
||||
* but I would recommend using a hook function where possible due to reduced
|
||||
* CPU usage and latency.
|
||||
*
|
||||
* This example implements only the reception of the stream, but it can be paired
|
||||
* with the sending example to complete the demonstration.
|
||||
*/
|
||||
|
||||
// parameters of this example. You may change these to reflect you network environment
|
||||
constexpr uint16_t LOCAL_PORT = 8890;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8888;
|
||||
|
||||
// How long this example will run
|
||||
constexpr auto RECEIVE_TIME_MS = std::chrono::milliseconds(3000);
|
||||
constexpr int RECEIVER_WAIT_TIME_MS = 100;
|
||||
|
||||
void process_frame(uvgrtp::frame::rtp_frame *frame);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
std::cout << "Starting uvgRTP RTP receive hook example" << std::endl;
|
||||
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *sess = ctx.create_session(REMOTE_ADDRESS);
|
||||
int flags = RCE_NO_FLAGS;
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
uvgrtp::media_stream *receiver = sess->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_H265, flags);
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::media_stream *hevc = sess->create_stream(8888, 8889, RTP_FORMAT_H265, 0);
|
||||
// TODO: Explain how to stop poll in middle of the wait
|
||||
|
||||
/* pull_frame() will block until a frame is received.
|
||||
*
|
||||
* If that is not acceptable, a separate thread for the reader should be created */
|
||||
uvgrtp::frame::rtp_frame *frame = nullptr;
|
||||
if (receiver)
|
||||
{
|
||||
uvgrtp::frame::rtp_frame *frame = nullptr;
|
||||
|
||||
while (!(frame = hevc->pull_frame())) {
|
||||
/* When we receive a frame, the ownership of the frame belongs to us and
|
||||
* when we're done with it, we need to deallocate the frame */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
std::cout << "Start receiving frames for " << RECEIVE_TIME_MS.count() << " ms" << std::endl;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
while (std::chrono::steady_clock::now() - start < RECEIVE_TIME_MS)
|
||||
{
|
||||
/* You can specify a timeout for the operation and if the a frame is not received
|
||||
* within that time limit, pull_frame() returns a nullptr
|
||||
*
|
||||
* The parameter tells how long time a frame is waited in milliseconds */
|
||||
frame = receiver->pull_frame(RECEIVER_WAIT_TIME_MS);
|
||||
|
||||
if (frame)
|
||||
process_frame(frame);
|
||||
}
|
||||
|
||||
sess->destroy_stream(receiver);
|
||||
}
|
||||
|
||||
/* You can also specify for a timeout for the operation and if the a frame is not received
|
||||
* within that time limit, pull_frame() returns a nullptr
|
||||
*
|
||||
* The parameter tells how long time a frame is waited in milliseconds */
|
||||
frame = hevc->pull_frame(200);
|
||||
if (sess)
|
||||
{
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
}
|
||||
|
||||
/* Frame must be freed manually */
|
||||
uvgrtp::frame::dealloc_frame(frame);
|
||||
|
||||
ctx.destroy_session(sess);
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void process_frame(uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
std::cout << "Received an RTP frame" << std::endl;
|
||||
|
||||
/* When we receive a frame, the ownership of the frame belongs to us and
|
||||
* when we're done with it, we need to deallocate the frame */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
|
|
@ -1,55 +1,192 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
#include <cstring>
|
||||
|
||||
/* uvgRTP calls this hook when it receives an RTCP Receiver Report
|
||||
/* RTCP (RTP Control Protocol) is used to monitor the quality
|
||||
* of the RTP stream. This example demonstrates the usage of
|
||||
* sender and receiver reports. RTCP also includes SDES, APP and BYE
|
||||
* packets which are not demostrated in this example.
|
||||
*
|
||||
* This example shows the usage of rtcp while also transmitting RTP
|
||||
* stream. The rtcp reports are sent only every 10 seconds and the
|
||||
* sender/receiver reports are printed.
|
||||
*/
|
||||
|
||||
constexpr char LOCAL_INTERFACE[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
constexpr uint16_t PAYLOAD_LEN = 256;
|
||||
constexpr uint16_t FRAME_RATE = 30;
|
||||
constexpr uint32_t EXAMPLE_RUN_TIME_S = 30;
|
||||
constexpr int SEND_TEST_PACKETS = FRAME_RATE*EXAMPLE_RUN_TIME_S;
|
||||
constexpr int PACKET_INTERVAL_MS = 1000/FRAME_RATE;
|
||||
|
||||
/* uvgRTP calls this hook when it receives an RTCP Report
|
||||
*
|
||||
* NOTE: If application uses hook, it must also free the frame when it's done with i
|
||||
* Frame must deallocated using uvgrtp::frame::dealloc_frame() function */
|
||||
void receiver_hook(uvgrtp::frame::rtcp_receiver_report *frame);
|
||||
void sender_hook(uvgrtp::frame::rtcp_sender_report *frame);
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, int frame_index);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
std::cout << "Starting uvgRTP RTCP hook example" << std::endl;
|
||||
|
||||
// Creation of RTP stream. See sending example for more details
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *local_session = ctx.create_session(REMOTE_ADDRESS);
|
||||
uvgrtp::session *remote_session = ctx.create_session(LOCAL_INTERFACE);
|
||||
|
||||
int flags = RCE_RTCP;
|
||||
uvgrtp::media_stream *local_stream = local_session->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
uvgrtp::media_stream *remote_stream = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
// TODO: There is a bug in uvgRTP in how sender reports are implemented and this text reflects
|
||||
// that wrong thinking. Sender reports are sent by the sender
|
||||
|
||||
/* In this example code, local_stream acts as the sender and because it is the only sender,
|
||||
* it does not send any RTCP frames but only receives RTCP Receiver reports from remote_stream.
|
||||
*
|
||||
* Because local_stream only sends and remote_stream only receives, we only need to install
|
||||
* receive hook for local_stream.
|
||||
*
|
||||
* By default, all media_stream that have RTCP enabled start as receivers and only if/when they
|
||||
* call push_frame() are they converted into senders. */
|
||||
|
||||
if (!local_stream || local_stream->get_rtcp()->install_receiver_hook(receiver_hook) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to install RTCP receiver report hook" << std::endl;
|
||||
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!remote_stream || remote_stream->get_rtcp()->install_sender_hook(sender_hook) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to install RTCP sender report hook" << std::endl;
|
||||
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (local_stream)
|
||||
{
|
||||
// Send dummy data so there's some RTP data to analyze
|
||||
uint8_t buffer[PAYLOAD_LEN] = { 0 };
|
||||
memset(buffer, 'a', PAYLOAD_LEN);
|
||||
|
||||
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
|
||||
|
||||
for (unsigned int i = 0; i < SEND_TEST_PACKETS; ++i)
|
||||
{
|
||||
if ((i+1)%10 == 0 || i == 0) // print every 10 frames and first
|
||||
{
|
||||
std::cout << "Sending RTP frame " << (i + 1) << "/" << SEND_TEST_PACKETS
|
||||
<< " Total data sent: " << (i + 1)*PAYLOAD_LEN << std::endl;
|
||||
}
|
||||
|
||||
local_stream->push_frame((uint8_t *)buffer, PAYLOAD_LEN, RTP_NO_FLAGS);
|
||||
|
||||
// send frames at constant interval to mimic a real camera stream
|
||||
wait_until_next_frame(start, i);
|
||||
}
|
||||
|
||||
std::cout << "Sending finished, total time: " <<
|
||||
(std::chrono::steady_clock::now() - start).count()/1000000 <<" ms" << std::endl;
|
||||
}
|
||||
|
||||
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void receiver_hook(uvgrtp::frame::rtcp_receiver_report *frame)
|
||||
{
|
||||
LOG_INFO("Received an RTCP Receiver Report");
|
||||
std::cout << "RTCP receiver report! ----------" << std::endl;
|
||||
|
||||
for (auto& block : frame->report_blocks) {
|
||||
fprintf(stderr, "ssrc: %x\n", block.ssrc);
|
||||
fprintf(stderr, "fraction: %u\n", block.fraction);
|
||||
fprintf(stderr, "lost: %d\n", block.lost);
|
||||
fprintf(stderr, "last_seq: %u\n", block.last_seq);
|
||||
fprintf(stderr, "jitter: %u\n", block.jitter);
|
||||
fprintf(stderr, "lsr: %u\n", block.lsr);
|
||||
fprintf(stderr, "dlsr (ms): %u\n", uvgrtp::clock::jiffies_to_ms(block.dlsr));
|
||||
for (auto& block : frame->report_blocks)
|
||||
{
|
||||
std::cout << "ssrc: " << block.ssrc << std::endl;
|
||||
std::cout << "fraction: " << block.fraction << std::endl;
|
||||
std::cout << "lost: " << block.lost << std::endl;
|
||||
std::cout << "last_seq: " << block.last_seq << std::endl;
|
||||
std::cout << "jitter: " << block.jitter << std::endl;
|
||||
std::cout << "lsr: " << block.lsr << std::endl;
|
||||
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
|
||||
/* RTCP frames can be deallocated using delete */
|
||||
delete frame;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
void sender_hook(uvgrtp::frame::rtcp_sender_report *frame)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
std::cout << "RTCP sender report! ----------" << std::endl;
|
||||
std::cout << "NTP msw: " << frame->sender_info.ntp_msw << std::endl;
|
||||
std::cout << "NTP lsw: " << frame->sender_info.ntp_lsw << std::endl;
|
||||
std::cout << "RTP timestamp: " << frame->sender_info.rtp_ts << std::endl;
|
||||
std::cout << "packet count: " << frame->sender_info.pkt_cnt << std::endl;
|
||||
std::cout << "byte count: " << frame->sender_info.byte_cnt << std::endl;
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
|
||||
/* For s1, RTCP runner is using port 7778 and for s2 port 8889 */
|
||||
uvgrtp::media_stream *s1 = sess->create_stream(7777, 8888, RTP_FORMAT_GENERIC, RCE_RTCP);
|
||||
uvgrtp::media_stream *s2 = sess->create_stream(8888, 7777, RTP_FORMAT_GENERIC, RCE_RTCP);
|
||||
|
||||
/* In this example code, s1 acts as the sender and because it is the only sender,
|
||||
* it does not send any RTCP frames but only receives RTCP Receiver reports from s2.
|
||||
*
|
||||
* Because s1 only sends and s2 only receives, we only need to install receive hook for s1
|
||||
*
|
||||
* By default, all media_stream that have RTCP enabled start as receivers and only if/when they
|
||||
* call push_frame() are they converted into senders. */
|
||||
(void)s1->get_rtcp()->install_receiver_hook(receiver_hook);
|
||||
|
||||
/* Send dummy data so there's some RTCP data to send */
|
||||
uint8_t buffer[50] = { 0 };
|
||||
memset(buffer, 'a', 50);
|
||||
|
||||
while (true) {
|
||||
s1->push_frame((uint8_t *)buffer, 50, RTP_NO_FLAGS);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
for (auto& block : frame->report_blocks)
|
||||
{
|
||||
std::cout << "ssrc: " << block.ssrc << std::endl;
|
||||
std::cout << "fraction: " << block.fraction << std::endl;
|
||||
std::cout << "lost: " << block.lost << std::endl;
|
||||
std::cout << "last_seq: " << block.last_seq << std::endl;
|
||||
std::cout << "jitter: " << block.jitter << std::endl;
|
||||
std::cout << "lsr: " << block.lsr << std::endl;
|
||||
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
|
||||
/* RTCP frames can be deallocated using delete */
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point &start, int frame_index)
|
||||
{
|
||||
// wait until it is time to send the next frame. Simulates a steady sending pace
|
||||
// and included only for demostration purposes since you can use uvgRTP to send
|
||||
// packets as fast as desired
|
||||
auto time_since_start = std::chrono::steady_clock::now() - start;
|
||||
auto next_frame_time = (frame_index + 1)*std::chrono::milliseconds(PACKET_INTERVAL_MS);
|
||||
if (next_frame_time > time_since_start)
|
||||
{
|
||||
std::this_thread::sleep_for(next_frame_time - time_since_start);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context &ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive)
|
||||
{
|
||||
if (send)
|
||||
{
|
||||
local_session->destroy_stream(send);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
{
|
||||
remote_session->destroy_stream(receive);
|
||||
}
|
||||
|
||||
if (local_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(local_session);
|
||||
}
|
||||
|
||||
if (remote_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(remote_session);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,39 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
|
||||
#define PAYLOAD_MAXLEN 100
|
||||
#include <iostream>
|
||||
|
||||
/* RTP is a protocol for real-time streaming. The simplest usage
|
||||
* scenario is sending one RTP stream and receiving it. This example
|
||||
* Shows how to send one RTP stream. These examples perform a simple
|
||||
* test if they are run. You may run the receiving examples at the same
|
||||
* time to see the whole demo. */
|
||||
|
||||
/* parameters of this example. You may change these to reflect
|
||||
* you network environment. */
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
// the parameters of demostration
|
||||
constexpr size_t PAYLOAD_LEN = 100;
|
||||
constexpr int AMOUNT_OF_TEST_PACKETS = 100;
|
||||
constexpr auto END_WAIT = std::chrono::seconds(5);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
std::cout << "Starting uvgRTP RTP sending example" << std::endl;
|
||||
|
||||
/* To use the library, one must create a global RTP context object */
|
||||
uvgrtp::context ctx;
|
||||
|
||||
/* Each new IP address requires a separate RTP session */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
// A session represents
|
||||
uvgrtp::session *sess = ctx.create_session(REMOTE_ADDRESS);
|
||||
|
||||
/* Each RTP session has one or more media streams. These media streams are bidirectional
|
||||
* and they require both source and destination ports for the connection. One must also
|
||||
* specify the media format for the stream and any configuration flags if needed.
|
||||
*
|
||||
* See configuration.cc for more details about configuration.
|
||||
* See Configuration example for more details about configuration.
|
||||
*
|
||||
* First port is source port aka the port that we listen to and second port is the port
|
||||
* that remote listens to
|
||||
|
@ -22,18 +41,42 @@ int main(void)
|
|||
* This same object is used for both sending and receiving media
|
||||
*
|
||||
* In this example, we have one media stream with the remote participant: H265 */
|
||||
uvgrtp::media_stream *hevc = sess->create_stream(8888, 8889, RTP_FORMAT_H265, RTP_NO_FLAGS);
|
||||
|
||||
uint8_t *buffer = new uint8_t[PAYLOAD_MAXLEN];
|
||||
int flags = RTP_NO_FLAGS;
|
||||
uvgrtp::media_stream *hevc = sess->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_H265, flags);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (hevc->push_frame(buffer, PAYLOAD_MAXLEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "Failed to send RTP frame!");
|
||||
if (hevc)
|
||||
{
|
||||
/* In this example we send packets as fast as possible. The source can be
|
||||
* a file or a real-time encoded stream */
|
||||
for (int i = 0; i < AMOUNT_OF_TEST_PACKETS; ++i)
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> dummy_frame = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
|
||||
|
||||
if ((i+1)%10 == 0 || i == 0) // print every 10 frames and first
|
||||
std::cout << "Sending frame " << i + 1 << '/' << AMOUNT_OF_TEST_PACKETS << std::endl;
|
||||
|
||||
if (hevc->push_frame(std::move(dummy_frame), PAYLOAD_LEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
std::cout << "Failed to send RTP frame!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Sending finished. Waiting "<< END_WAIT.count()
|
||||
<< " seconds before exiting." << std::endl;
|
||||
|
||||
// wait a little bit so pop-up console users have time to see the results
|
||||
std::this_thread::sleep_for(END_WAIT);
|
||||
|
||||
sess->destroy_stream(hevc);
|
||||
}
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
delete[] buffer;
|
||||
ctx.destroy_session(sess);
|
||||
if (sess)
|
||||
{
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,40 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
#include <climits>
|
||||
|
||||
#define PAYLOAD_MAXLEN (0xffff - 0x1000)
|
||||
/* Generic sending API means, that the user takes the responsibility
|
||||
* for RTP payload format. uvgRTP does help a little bit by offering
|
||||
* fragmentation function for sending. This means that that if the
|
||||
* packet is larger than the specified RTP payload size (default is 1500)
|
||||
* the packets are fragmented. This is useful with raw audio of high quality,
|
||||
* but unfortenately uvgRTP does not offer full raw-format support.
|
||||
* Contributions are welcome.
|
||||
*
|
||||
* This example demonstrates both sending and receiving of a generic stream. */
|
||||
|
||||
|
||||
// network parameters of the example
|
||||
constexpr char LOCAL_INTERFACE[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
// demonstration parameters of the example
|
||||
constexpr uint32_t PAYLOAD_MAXLEN = (0xffff - 0x1000);
|
||||
constexpr int TEST_PACKETS = 100;
|
||||
|
||||
void rtp_receive_hook(void *arg, uvgrtp::frame::rtp_frame *frame);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
std::cout << "Starting uvgRTP generic RTP payload sending example" << std::endl;
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
// See sending example for more details
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *local_session = ctx.create_session(REMOTE_ADDRESS);
|
||||
uvgrtp::session *remote_session = ctx.create_session(LOCAL_INTERFACE);
|
||||
|
||||
/* To enable interoperability between RTP libraries, uvgRTP won't fragment generic frames by default.
|
||||
*
|
||||
|
@ -22,74 +47,94 @@ int main(void)
|
|||
* received, uvgRTP constructs one full RTP frame from the fragments and returns the frame to user.
|
||||
*
|
||||
* See sending.cc for more details about create_stream() */
|
||||
uvgrtp::media_stream *send = sess->create_stream(8888, 8889, RTP_FORMAT_GENERIC, RCE_FRAGMENT_GENERIC);
|
||||
uvgrtp::media_stream *recv = sess->create_stream(8889, 8888, RTP_FORMAT_GENERIC, RCE_FRAGMENT_GENERIC);
|
||||
|
||||
/* Notice that PAYLOAD_MAXLEN > MTU (4096 > 1500).
|
||||
int flags = RCE_FRAGMENT_GENERIC;
|
||||
uvgrtp::media_stream *send = local_session->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
uvgrtp::media_stream *recv = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
if (!recv || recv->install_receive_hook(nullptr, rtp_receive_hook) != RTP_OK)
|
||||
{
|
||||
cleanup(ctx, local_session, remote_session, send, recv);
|
||||
std::cerr << "Failed to install RTP receive hook!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (send)
|
||||
{
|
||||
/* Notice that PAYLOAD_MAXLEN > MTU (4096 > 1500).
|
||||
*
|
||||
* uvgRTP fragments all generic input frames that are larger than 1500 and in the receiving end,
|
||||
* it will reconstruct the full sent frame from fragments when all fragments have been received */
|
||||
auto media = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_MAXLEN]);
|
||||
auto media = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_MAXLEN]);
|
||||
|
||||
srand(time(NULL));
|
||||
srand(time(NULL));
|
||||
|
||||
while (true) {
|
||||
int size = (rand() % PAYLOAD_MAXLEN) + 1;
|
||||
for (int i = 0; i < TEST_PACKETS; ++i)
|
||||
{
|
||||
int random_packet_size = (rand() % PAYLOAD_MAXLEN) + 1;
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
media[i] = (i + size) % CHAR_MAX;
|
||||
for (int i = 0; i < random_packet_size; ++i)
|
||||
{
|
||||
media[i] = (i + random_packet_size) % CHAR_MAX;
|
||||
}
|
||||
|
||||
if (send->push_frame(media.get(), size, RTP_NO_FLAGS) != RTP_OK) {
|
||||
fprintf(stderr, "Failed to send frame!\n");
|
||||
return -1;
|
||||
}
|
||||
std::cout << "Sending RTP frame " << i + 1 << '/' << TEST_PACKETS
|
||||
<< ". Payload size: " << random_packet_size << std::endl;
|
||||
|
||||
auto frame = recv->pull_frame();
|
||||
|
||||
if (memcmp(frame->payload, media.get(), size))
|
||||
LOG_ERROR("frame is corrupted!");
|
||||
|
||||
fprintf(stderr, "received frame of size %u, rand %d\n", frame->payload_len, size);
|
||||
|
||||
uvgrtp::frame::dealloc_frame(frame);
|
||||
if (send->push_frame(media.get(), random_packet_size, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
cleanup(ctx, local_session, remote_session, send, recv);
|
||||
std::cerr << "Failed to send frame!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < PAYLOAD_MAXLEN; ++i)
|
||||
custom_media[i] = i % CHAR_MAX;
|
||||
|
||||
if (send->push_frame(std::move(custom_media), PAYLOAD_MAXLEN, RTP_NO_FLAGS) != RTP_OK) {
|
||||
fprintf(stderr, "Failed to send frame!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto frame = recv->pull_frame();
|
||||
|
||||
/* Verify that all packets were received without corruption */
|
||||
for (int i = 0; i < PAYLOAD_MAXLEN; ++i) {
|
||||
if (frame->payload[i] != (i % CHAR_MAX))
|
||||
fprintf(stderr, "frame was corrupted during transfer!\n");
|
||||
}
|
||||
|
||||
/* the frame must be destroyed manually */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
|
||||
/* The input data size doesn't always have to be larger than MTU,
|
||||
* i.e., you can still send small packets */
|
||||
uint8_t data[5] = { 0x1, 0x5, 0xa, 0x77, 0xff };
|
||||
|
||||
send->push_frame(data, sizeof(data), 0);
|
||||
frame = recv->pull_frame();
|
||||
|
||||
if (memcmp(data, frame->payload, 5))
|
||||
fprintf(stderr, "frame was corrupted during transfer!\n");
|
||||
|
||||
/* the frame must be destroyed manually */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
#endif
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
ctx.destroy_session(sess);
|
||||
ctx.destroy_session(local_session);
|
||||
ctx.destroy_session(remote_session);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void rtp_receive_hook(void *arg, uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
std::cout << "Received RTP frame. Payload size: " << frame->payload_len << std::endl;
|
||||
|
||||
/* Now we own the frame. Here you could give the frame to the application
|
||||
* if f.ex "arg" was some application-specific pointer
|
||||
*
|
||||
* arg->copy_frame(frame) or whatever
|
||||
*
|
||||
* When we're done with the frame, it must be deallocated manually */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context &ctx, uvgrtp::session *local_session, uvgrtp::session *remote_session,
|
||||
uvgrtp::media_stream *send, uvgrtp::media_stream *receive)
|
||||
{
|
||||
if (send)
|
||||
{
|
||||
local_session->destroy_stream(send);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
{
|
||||
remote_session->destroy_stream(receive);
|
||||
}
|
||||
|
||||
if (local_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(local_session);
|
||||
}
|
||||
|
||||
if (remote_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(remote_session);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,132 @@
|
|||
#include <uvgrtp/lib.hh>
|
||||
#include <climits>
|
||||
|
||||
#define PAYLOAD_MAXLEN 256
|
||||
#define KEY_SIZE 16
|
||||
#define SALT_SIZE 14
|
||||
|
||||
/* Key and salt for the SRTP session of sender and receiver
|
||||
/* Encryption is also supported by uvgRTP. Encryption is facilitated
|
||||
* by Secure RTP (SRTP) protocol. In order to use SRTP, the encryption
|
||||
* context must be exchanged in some way. uvgRTP offers two main methods
|
||||
* for exchanging the encryption contexts.
|
||||
*
|
||||
* NOTE: uvgRTP only supports 128 bit keys and 112 bit salts */
|
||||
uint8_t key[KEY_SIZE] = { 0 };
|
||||
uint8_t salt[SALT_SIZE] = { 0 };
|
||||
* This example presents the user implemented encryption key
|
||||
* negotiation. In this scenario the encryption keys are exchanged
|
||||
* by the application and handed over to uvgRTP. */
|
||||
|
||||
void thread_func(void)
|
||||
|
||||
// network parameters of example
|
||||
constexpr char SENDER_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char RECEIVER_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
// encryption parameters of example
|
||||
enum Key_length{SRTP_128 = 128, SRTP_196 = 196, SRTP_256 = 256};
|
||||
constexpr Key_length KEY_SIZE = SRTP_256;
|
||||
constexpr int KEY_SIZE_BYTES = KEY_SIZE/8;
|
||||
constexpr int SALT_SIZE = 112;
|
||||
constexpr int SALT_SIZE_BYTES = SALT_SIZE/8;
|
||||
|
||||
// demonstration parameters
|
||||
constexpr auto EXAMPLE_DURATION = std::chrono::seconds(5);
|
||||
constexpr int FRAME_RATE = 30; // fps
|
||||
constexpr int SEND_TEST_PACKETS = (EXAMPLE_DURATION.count() - 1)*FRAME_RATE;
|
||||
constexpr int PACKET_INTERVAL_MS = 1000/FRAME_RATE;
|
||||
constexpr int RECEIVER_WAIT_TIME_MS = 100;
|
||||
|
||||
void process_frame(uvgrtp::frame::rtp_frame *frame);
|
||||
void receive_func(uint8_t key[KEY_SIZE_BYTES], uint8_t salt[SALT_SIZE_BYTES]);
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, int frame_index);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uvgrtp::context ctx;
|
||||
|
||||
// first we check if crypto has been included before attempting to use it
|
||||
if (!ctx.crypto_enabled())
|
||||
{
|
||||
std::cerr << "Cannot run SRTP example if crypto is not included in uvgRTP!"
|
||||
<< std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Key and salt for the SRTP session of sender and receiver
|
||||
*
|
||||
* NOTE: uvgRTP supports 128, 196 and 256 bit keys and 112 bit salts */
|
||||
uint8_t key[KEY_SIZE_BYTES] = { 0 };
|
||||
uint8_t salt[SALT_SIZE_BYTES] = { 0 };
|
||||
|
||||
// initialize SRTP key and salt with dummy values
|
||||
for (int i = 0; i < KEY_SIZE_BYTES; ++i)
|
||||
key[i] = i;
|
||||
|
||||
for (int i = 0; i < SALT_SIZE_BYTES; ++i)
|
||||
salt[i] = i * 2;
|
||||
|
||||
std::cout << "Starting uvgRTP SRTP user provided encryption key example. Using key:"
|
||||
<< key << " and salt: " << salt << std::endl;
|
||||
|
||||
// Create separate thread for the receiver
|
||||
std::thread receiver(receive_func, key, salt);
|
||||
|
||||
// Enable SRTP and let user manage the keys
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER | RCE_SRTP_KEYSIZE_256;
|
||||
|
||||
uvgrtp::session *sender_session = ctx.create_session(RECEIVER_ADDRESS);
|
||||
uvgrtp::media_stream *send = sender_session->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
if (send)
|
||||
{
|
||||
/* When using user managed keys, before anything else can be done
|
||||
* the add_srtp_ctx() must be called with the user SRTP key and salt.
|
||||
*
|
||||
* All calls to "send" that try to modify and or/use the newly
|
||||
* created media stream before calling add_srtp_ctx() will fail
|
||||
* if SRTP is enabled */
|
||||
send->add_srtp_ctx(key, salt);
|
||||
|
||||
// All media is now encrypted/decrypted automatically
|
||||
char *message = (char *)"Hello, world!";
|
||||
size_t msg_len = strlen(message);
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < SEND_TEST_PACKETS; ++i)
|
||||
{
|
||||
if ((i+1)%10 == 0 || i == 0) // print every 10 frames and first
|
||||
std::cout << "Sending frame # " << i + 1 << '/' << SEND_TEST_PACKETS << std::endl;
|
||||
|
||||
if (send->push_frame((uint8_t *)message, msg_len, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to send frame" << std::endl;
|
||||
}
|
||||
|
||||
// wait until it is time to send the next frame. Included only for
|
||||
// demostration purposes since you can use uvgRTP to send packets as fast as desired
|
||||
wait_until_next_frame(start, i);
|
||||
}
|
||||
|
||||
sender_session->destroy_stream(send);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to create SRTP sender" << std::endl;
|
||||
}
|
||||
|
||||
if (receiver.joinable())
|
||||
{
|
||||
receiver.join();
|
||||
}
|
||||
|
||||
if (sender_session)
|
||||
ctx.destroy_session(sender_session);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void receive_func(uint8_t key[KEY_SIZE_BYTES], uint8_t salt[SALT_SIZE_BYTES])
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
uvgrtp::session *receiver_session = ctx.create_session(SENDER_ADDRESS);
|
||||
|
||||
/* Enable SRTP and let user manage keys */
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
|
||||
|
@ -23,64 +134,70 @@ void thread_func(void)
|
|||
/* With user-managed keys, you have the option to use 192- and 256-bit keys.
|
||||
*
|
||||
* If 192- or 256-bit key size is specified in the flags, add_srtp_ctx() expects
|
||||
* the key paramter to be 24 or 32 bytes long, respectively. */
|
||||
if (0)
|
||||
flags |= RCE_SRTP_KEYSIZE_192;
|
||||
* the key parameter to be 24 or 32 bytes long, respectively. */
|
||||
flags |= RCE_SRTP_KEYSIZE_256;
|
||||
|
||||
/* See sending.cc for more details about create_stream() */
|
||||
uvgrtp::media_stream *recv = sess->create_stream(8889, 8888, RTP_FORMAT_GENERIC, flags);
|
||||
uvgrtp::media_stream *recv = receiver_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
/* Before anything else can be done,
|
||||
* add_srtp_ctx() must be called with the SRTP key and salt.
|
||||
*
|
||||
* All calls to "recv" that try to modify and or/use the newly
|
||||
* created media stream before calling add_srtp_ctx() will fail */
|
||||
recv->add_srtp_ctx(key, salt);
|
||||
// Receive frames by pulling for EXAMPLE_DURATION milliseconds
|
||||
if (recv)
|
||||
{
|
||||
/* Before anything else can be done,
|
||||
* add_srtp_ctx() must be called with the SRTP key and salt.
|
||||
*
|
||||
* All calls to "recv" that try to modify and or/use the newly
|
||||
* created media stream before calling add_srtp_ctx() will fail */
|
||||
recv->add_srtp_ctx(key, salt);
|
||||
|
||||
for (;;) {
|
||||
auto frame = recv->pull_frame();
|
||||
fprintf(stderr, "Message: '%s'\n", frame->payload);
|
||||
std::cout << "Start receiving frames for " << EXAMPLE_DURATION.count() << " s" << std::endl;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
/* the frame must be destroyed manually */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
uvgrtp::frame::rtp_frame *frame = nullptr;
|
||||
while (std::chrono::steady_clock::now() - start < EXAMPLE_DURATION)
|
||||
{
|
||||
/* You can specify a timeout for the operation and if the a frame is not received
|
||||
* within that time limit, pull_frame() returns a nullptr
|
||||
*
|
||||
* The parameter tells how long time a frame is waited in milliseconds */
|
||||
|
||||
frame = recv->pull_frame(RECEIVER_WAIT_TIME_MS);
|
||||
if (frame)
|
||||
{
|
||||
process_frame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
receiver_session->destroy_stream(recv);
|
||||
}
|
||||
|
||||
if (receiver_session)
|
||||
{
|
||||
ctx.destroy_session(receiver_session);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
void process_frame(uvgrtp::frame::rtp_frame *frame)
|
||||
{
|
||||
/* initialize SRTP key and salt */
|
||||
for (int i = 0; i < KEY_SIZE; ++i)
|
||||
key[i] = i;
|
||||
std::string payload = std::string((char*)frame->payload, frame->payload_len);
|
||||
|
||||
for (int i = 0; i < SALT_SIZE; ++i)
|
||||
salt[i] = i * 2;
|
||||
std::cout << "Received SRTP frame. Payload: " << payload << std::endl;
|
||||
|
||||
/* Create separate thread for the receiver */
|
||||
new std::thread(thread_func);
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
|
||||
/* Enable SRTP and let user manage keys */
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
|
||||
|
||||
/* See sending.cc for more details about create_stream() */
|
||||
uvgrtp::media_stream *send = sess->create_stream(8888, 8889, RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
/* Before anything else can be done,
|
||||
* add_srtp_ctx() must be called with the SRTP key and salt.
|
||||
*
|
||||
* All calls to "send" that try to modify and or/use the newly
|
||||
* created media stream before calling add_srtp_ctx() will fail */
|
||||
send->add_srtp_ctx(key, salt);
|
||||
|
||||
/* All media is now encrypted/decrypted automatically */
|
||||
char *message = (char *)"Hello, world!";
|
||||
size_t msg_len = strlen(message);
|
||||
|
||||
for (;;) {
|
||||
send->push_frame((uint8_t *)message, msg_len, RTP_NO_FLAGS);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
/* When we receive a frame, the ownership of the frame belongs to us and
|
||||
* when we're done with it, we need to deallocate the frame */
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point &start, int frame_index)
|
||||
{
|
||||
// wait until it is time to send the next frame. Simulates a steady sending pace
|
||||
// and included only for demostration purposes since you can use uvgRTP to send
|
||||
// packets as fast as desired
|
||||
auto time_since_start = std::chrono::steady_clock::now() - start;
|
||||
auto next_frame_time = (frame_index + 1)*std::chrono::milliseconds(PACKET_INTERVAL_MS);
|
||||
if (next_frame_time > time_since_start)
|
||||
{
|
||||
std::this_thread::sleep_for(next_frame_time - time_since_start);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
TEMPLATE = app
|
||||
CONFIG += console c++11
|
||||
CONFIG -= app_bundle
|
||||
CONFIG -= qt
|
||||
|
||||
# define here which example you want to build. Remember to rerun qmake
|
||||
CONFIG += selectBinding
|
||||
|
||||
selectBinding {
|
||||
DEFINES += __RTP_NO_CRYPTO__
|
||||
message("Building binding example.")
|
||||
TARGET = Binding
|
||||
SOURCES += \
|
||||
binding.cc \
|
||||
}
|
||||
|
||||
selectConfiguration {
|
||||
message("Building configuration example.")
|
||||
TARGET = Configuration
|
||||
SOURCES += \
|
||||
configuration.cc \
|
||||
}
|
||||
|
||||
selectCustomTimestamps {
|
||||
message("Building timestamp example.")
|
||||
TARGET = Timestamp
|
||||
SOURCES += \
|
||||
custom_timestamps.cc \
|
||||
}
|
||||
|
||||
selectReceiveHook {
|
||||
message("Building receive hook example.")
|
||||
TARGET = ReceiveHook
|
||||
SOURCES += \
|
||||
receiving_hook.cc \
|
||||
}
|
||||
|
||||
selectReceivePoll {
|
||||
message("Building receive poll example.")
|
||||
TARGET = ReceivePoll
|
||||
SOURCES += \
|
||||
receiving_poll.cc \
|
||||
}
|
||||
|
||||
selectRTCPhook {
|
||||
message("Building RTCP hook example.")
|
||||
TARGET = RTCPHook
|
||||
SOURCES += \
|
||||
rtcp_hook.cc \
|
||||
}
|
||||
|
||||
configSending {
|
||||
message("Building sending example.")
|
||||
TARGET = Sending
|
||||
SOURCES += \
|
||||
sending.cc \
|
||||
}
|
||||
|
||||
selectSendingGeneric {
|
||||
message("Building generic sending example.")
|
||||
TARGET = SendingGeneric
|
||||
SOURCES += \
|
||||
sending_generic.cc \
|
||||
}
|
||||
|
||||
selectSRTPUser {
|
||||
message("Building user managed SRTP example.")
|
||||
TARGET = SRTPUser
|
||||
SOURCES += \
|
||||
srtp_user.cc \
|
||||
|
||||
}
|
||||
|
||||
selectZRTPMultistream {
|
||||
message("Building ZRTP multistream example.")
|
||||
TARGET = ZRTPMultistream
|
||||
SOURCES += \
|
||||
zrtp_multistream.cc \
|
||||
}
|
||||
|
||||
DISTFILES += \
|
||||
README.md
|
||||
|
||||
|
||||
# uvgrtp include folder
|
||||
INCLUDEPATH += ../../include
|
||||
|
||||
LIBS += -luvgrtp
|
||||
|
||||
# uvgRTP links agains Crypto++ if it is available and excluded.
|
||||
# You can safely remove its linking if you did not include Crypto++ in uvgRTP.
|
||||
# Please note that the SRTP and ZRTP examples need Crypto++ to succeed
|
||||
win32-msvc{
|
||||
LIBS += -lcryptlib
|
||||
} else {
|
||||
LIBS += -lcryptopp
|
||||
}
|
||||
|
||||
win32-msvc{
|
||||
message("Detected MSVC compiler")
|
||||
# find the libraries if uvgrtp has been built using CMake instructions
|
||||
CONFIG(debug, debug|release) {
|
||||
UVGRTP_LIB_FOLDER = -L$$PWD/../../build/Debug
|
||||
} else:CONFIG(release, debug|release) {
|
||||
UVGRTP_LIB_FOLDER = -L$$PWD/../../build/Release
|
||||
}
|
||||
|
||||
LIBS += -lws2_32
|
||||
LIBS += -ladvapi32
|
||||
|
||||
LIBS += $${UVGRTP_LIB_FOLDER}
|
||||
message("Using the following folder for uvgRTP library:" $${UVGRTP_LIB_FOLDER})
|
||||
}
|
|
@ -2,62 +2,211 @@
|
|||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
void thread_func(void)
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
/* Zimmermann RTP (ZRTP) is a key management protocol for SRTP. Compared
|
||||
* to most approaches, using ZRTP can facilitate end-to-end encryption
|
||||
* of media traffic since the keys are exchanged peer-to-peer.
|
||||
*
|
||||
* Using ZRTP in uvgRTP requires only setting it on with RCE_SRTP_KMNGMNT_ZRTP
|
||||
* flag. Then when creating the media streams, you will encounter a small additional
|
||||
* wait until the ZRTP negotiation has been completed. ZRTP has to only be negotiatiated
|
||||
* once per session, since the following media_streams can use the key context from
|
||||
* the first media_stream.
|
||||
*
|
||||
* This example demonstrates usign the ZRTP to negotiate SRTP encryption context
|
||||
* for multiple media_streams. There are two senders and two receivers representing
|
||||
* video and audio streams.
|
||||
*/
|
||||
|
||||
/* Enable SRTP and use ZRTP to manage keys */
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP;
|
||||
// Network parameters of this example
|
||||
constexpr char SENDER_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t SENDER_VIDEO_PORT = 8888;
|
||||
constexpr uint16_t SENDER_AUDIO_PORT = 8890;
|
||||
|
||||
/* Keys creates using Diffie-Hellman mode */
|
||||
uvgrtp::media_stream *video = sess->create_stream(8889, 8888, RTP_FORMAT_GENERIC, flags);
|
||||
constexpr char RECEIVER_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t RECEIVER_VIDEO_PORT = 7776;
|
||||
constexpr uint16_t RECEIVER_AUDIO_PORT = 7778;
|
||||
|
||||
/* Keys created using Multistream mode */
|
||||
uvgrtp::media_stream *audio = sess->create_stream(7778, 7777, RTP_FORMAT_GENERIC, flags);
|
||||
// demonstration parameters of this example
|
||||
constexpr int VIDEO_PAYLOAD_SIZE = 4000;
|
||||
constexpr int AUDIO_PAYLOAD_SIZE = 100;
|
||||
|
||||
for (;;) {
|
||||
auto frame = video->pull_frame();
|
||||
fprintf(stderr, "Message: '%s'\n", frame->payload);
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
constexpr auto EXAMPLE_RUN_TIME_S = std::chrono::seconds(5);
|
||||
constexpr auto RECEIVER_WAIT_TIME_MS = std::chrono::milliseconds(50);
|
||||
|
||||
frame = audio->pull_frame();
|
||||
fprintf(stderr, "Message: '%s'\n", frame->payload);
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
}
|
||||
constexpr auto AUDIO_FRAME_INTERVAL_MS = std::chrono::milliseconds(20);
|
||||
|
||||
constexpr auto VIDEO_FRAME_INTERVAL_MS = std::chrono::milliseconds(1000/60); // 60 fps video
|
||||
|
||||
void receive_function(uvgrtp::session* receiver_session, int flags, std::shared_ptr<std::mutex> print_mutex,
|
||||
RTP_FORMAT format, uint16_t receiver_port, uint16_t sender_port);
|
||||
void sender_function(uvgrtp::session* sender_session, int flags, std::shared_ptr<std::mutex> print_mutex,
|
||||
RTP_FORMAT format, uint16_t sender_port, uint16_t receiver_port, size_t payload_size,
|
||||
std::chrono::milliseconds frame_interval);
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, std::chrono::milliseconds interval, int frame_index);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
std::cout << "Starting uvgRTP SRTP together with ZRTP example" << std::endl;
|
||||
|
||||
uvgrtp::context receiver_ctx;
|
||||
|
||||
// check that Crypto++ has been compiled into uvgRTP, otherwise encryption wont work.
|
||||
if (!receiver_ctx.crypto_enabled())
|
||||
{
|
||||
std::cerr << "Cannot run SRTP example if crypto++ is not included in uvgRTP!"
|
||||
<< std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uvgrtp::session *receiver_session = receiver_ctx.create_session(SENDER_ADDRESS);
|
||||
|
||||
std::shared_ptr<std::mutex> print_mutex = std::shared_ptr<std::mutex> (new std::mutex);
|
||||
|
||||
/* Create separate thread for the receiver
|
||||
*
|
||||
* Because we're using ZRTP for SRTP key management,
|
||||
* the receiver and sender must communicate with each other
|
||||
* before the actual media communication starts */
|
||||
new std::thread(thread_func);
|
||||
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session *sess = ctx.create_session("127.0.0.1");
|
||||
// Enable SRTP and use ZRTP to manage keys for both sender and receiver*/
|
||||
unsigned rce_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP;
|
||||
|
||||
/* Enable SRTP and use ZRTP to manage keys */
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP;
|
||||
// start the receivers in a separate thread
|
||||
std::thread a_receiver(receive_function, receiver_session, rce_flags, print_mutex,
|
||||
RTP_FORMAT_OPUS, RECEIVER_AUDIO_PORT, SENDER_AUDIO_PORT);
|
||||
|
||||
/* Initialize ZRTP and negotiate the keys used to encrypt the media */
|
||||
uvgrtp::media_stream *video = sess->create_stream(8888, 8889, RTP_FORMAT_GENERIC, flags);
|
||||
std::thread v_receiver(receive_function, receiver_session, rce_flags, print_mutex,
|
||||
RTP_FORMAT_H266, RECEIVER_VIDEO_PORT, SENDER_VIDEO_PORT);
|
||||
|
||||
uvgrtp::context sender_ctx;
|
||||
uvgrtp::session *sender_session = sender_ctx.create_session(RECEIVER_ADDRESS);
|
||||
|
||||
// start the senders in their own threads
|
||||
std::thread a_sender(sender_function, sender_session, rce_flags, print_mutex,
|
||||
RTP_FORMAT_OPUS, SENDER_AUDIO_PORT, RECEIVER_AUDIO_PORT,
|
||||
AUDIO_PAYLOAD_SIZE, AUDIO_FRAME_INTERVAL_MS);
|
||||
|
||||
std::thread v_sender(sender_function, sender_session, rce_flags, print_mutex,
|
||||
RTP_FORMAT_H266, SENDER_VIDEO_PORT, RECEIVER_VIDEO_PORT,
|
||||
VIDEO_PAYLOAD_SIZE, VIDEO_FRAME_INTERVAL_MS);
|
||||
|
||||
// wait until all threads have ended
|
||||
if (a_receiver.joinable())
|
||||
{
|
||||
a_receiver.join();
|
||||
}
|
||||
if (v_receiver.joinable())
|
||||
{
|
||||
v_receiver.join();
|
||||
}
|
||||
if (a_sender.joinable())
|
||||
{
|
||||
a_sender.join();
|
||||
}
|
||||
if (v_sender.joinable())
|
||||
{
|
||||
v_sender.join();
|
||||
}
|
||||
|
||||
if (sender_session)
|
||||
sender_ctx.destroy_session(sender_session);
|
||||
|
||||
if (receiver_session)
|
||||
sender_ctx.destroy_session(receiver_session);
|
||||
|
||||
std::cout << "ZRTP example finished" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void receive_function(uvgrtp::session* receiver_session, int flags,
|
||||
std::shared_ptr<std::mutex> print_mutex,
|
||||
RTP_FORMAT format, uint16_t receiver_port, uint16_t sender_port)
|
||||
{
|
||||
/* Keys created using Multistream mode */
|
||||
uvgrtp::media_stream *receiver_stream =
|
||||
receiver_session->create_stream(receiver_port, sender_port, format, flags);
|
||||
|
||||
if (receiver_stream)
|
||||
{
|
||||
uvgrtp::frame::rtp_frame *frame = nullptr;
|
||||
|
||||
std::cout << "Start receiving frames for " << EXAMPLE_RUN_TIME_S.count()
|
||||
<< " seconds" << std::endl;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
while (std::chrono::steady_clock::now() - start < EXAMPLE_RUN_TIME_S)
|
||||
{
|
||||
/* You can specify a timeout for the operation and if the a frame is not received
|
||||
* within that time limit, pull_frame() returns a nullptr
|
||||
*
|
||||
* The parameter tells how long time a frame is waited in milliseconds */
|
||||
|
||||
frame = receiver_stream->pull_frame(RECEIVER_WAIT_TIME_MS.count());
|
||||
|
||||
if (frame)
|
||||
{
|
||||
print_mutex->lock();
|
||||
std::cout << "Received a frame. Payload size: " << frame->payload_len << std::endl;
|
||||
print_mutex->unlock();
|
||||
|
||||
// Process the frame here
|
||||
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
receiver_session->destroy_stream(receiver_stream);
|
||||
}
|
||||
}
|
||||
|
||||
void sender_function(uvgrtp::session* sender_session, int flags, std::shared_ptr<std::mutex> print_mutex,
|
||||
RTP_FORMAT format, uint16_t sender_port, uint16_t receiver_port, size_t payload_size,
|
||||
std::chrono::milliseconds frame_interval)
|
||||
{
|
||||
/* The first call to create_stream() creates keys for the session using Diffie-Hellman
|
||||
* key exchange and all subsequent calls to create_stream() initialize keys for the
|
||||
* stream using Multistream mode */
|
||||
uvgrtp::media_stream *audio = sess->create_stream(7777, 7778, RTP_FORMAT_GENERIC, flags);
|
||||
uvgrtp::media_stream *sender_audio_strm = sender_session->create_stream(sender_port,
|
||||
receiver_port,
|
||||
format, flags);
|
||||
|
||||
char *message = (char *)"Hello, world!";
|
||||
size_t msg_len = strlen(message);
|
||||
if (sender_audio_strm)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
for (;;) {
|
||||
video->push_frame((uint8_t *)message, msg_len, RTP_NO_FLAGS);
|
||||
audio->push_frame((uint8_t *)message, msg_len, RTP_NO_FLAGS);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
for (int i = 0; std::chrono::steady_clock::now() < (start + EXAMPLE_RUN_TIME_S); ++i)
|
||||
{
|
||||
/*
|
||||
print_mutex->lock();
|
||||
std::cout << "Sending frame" << std::endl;
|
||||
print_mutex->unlock();
|
||||
*/
|
||||
|
||||
std::unique_ptr<uint8_t[]> dummy_audio_frame = std::unique_ptr<uint8_t[]>(new uint8_t[payload_size]);
|
||||
|
||||
if (sender_audio_strm->push_frame(std::move(dummy_audio_frame), payload_size, RTP_NO_FLAGS) != RTP_OK)
|
||||
{
|
||||
std::cerr << "Failed to send frame" << std::endl;
|
||||
}
|
||||
|
||||
// wait until it is time to send the next frame. Included only for
|
||||
// demostration purposes since you can use uvgRTP to send packets as fast as desired
|
||||
wait_until_next_frame(start, frame_interval, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start,
|
||||
std::chrono::milliseconds interval, int frame_index)
|
||||
{
|
||||
// wait until it is time to send the next frame. Simulates a steady sending pace
|
||||
// and included only for demostration purposes since you can use uvgRTP to send
|
||||
// packets as fast as desired
|
||||
auto time_since_start = std::chrono::steady_clock::now() - start;
|
||||
auto next_frame_time = (frame_index + 1)*interval;
|
||||
if (next_frame_time > time_since_start)
|
||||
{
|
||||
std::this_thread::sleep_for(next_frame_time - time_since_start);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,8 @@ namespace uvgrtp {
|
|||
std::string& get_cname();
|
||||
/// \endcond
|
||||
|
||||
bool crypto_enabled() const;
|
||||
|
||||
private:
|
||||
/* Generate CNAME for participant using host and login names */
|
||||
std::string generate_cname();
|
|
@ -1,6 +1,6 @@
|
|||
#include "clock.hh"
|
||||
#include "uvgrtp/clock.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "crypto.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "dispatch.hh"
|
||||
|
||||
#include "queue.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "runner.hh"
|
||||
#include "uvgrtp/runner.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include "../queue.hh"
|
||||
#include "../rtp.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "h26x.hh"
|
||||
#include "util.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
|
||||
#include "uvgrtp/clock.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
|
||||
#include <deque>
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
#include "../srtp/srtcp.hh"
|
||||
#include "../rtp.hh"
|
||||
#include "../queue.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "h26x.hh"
|
||||
#include "util.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
|
||||
#include "uvgrtp/clock.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
#include "../rtp.hh"
|
||||
#include "../queue.hh"
|
||||
#include "frame.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#include "h26x.hh"
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
#include "socket.hh"
|
||||
#include "frame.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/clock.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
|
||||
#include <deque>
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
#include "../rtp.hh"
|
||||
#include "../queue.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "media.hh"
|
||||
#include "util.hh"
|
||||
#include "socket.hh"
|
||||
#include "clock.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/clock.hh"
|
||||
|
||||
#include <deque>
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include "media.hh"
|
||||
|
||||
#include "../rtp.hh"
|
||||
#include "socket.hh"
|
||||
#include "../queue.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "frame.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "holepuncher.hh"
|
||||
|
||||
#include "clock.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/clock.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
|
||||
#define THRESHOLD 2000
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "runner.hh"
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/runner.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "hostname.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
//#include <windows.h>
|
||||
|
|
14
src/lib.cc
14
src/lib.cc
|
@ -1,10 +1,11 @@
|
|||
#include "lib.hh"
|
||||
#include "uvgrtp/lib.hh"
|
||||
|
||||
#include "uvgrtp/version.hh"
|
||||
#include "uvgrtp/session.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "hostname.hh"
|
||||
#include "random.hh"
|
||||
#include "session.hh"
|
||||
#include "version.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -80,3 +81,8 @@ std::string& uvgrtp::context::get_cname()
|
|||
{
|
||||
return cname_;
|
||||
}
|
||||
|
||||
bool uvgrtp::context::crypto_enabled() const
|
||||
{
|
||||
return uvgrtp::crypto::enabled();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#include "media_stream.hh"
|
||||
#include "uvgrtp/media_stream.hh"
|
||||
|
||||
#include "formats/h264.hh"
|
||||
#include "formats/h265.hh"
|
||||
#include "formats/h266.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "random.hh"
|
||||
#include "rtp.hh"
|
||||
#include "zrtp.hh"
|
||||
|
||||
#include "holepuncher.hh"
|
||||
#include "pkt_dispatch.hh"
|
||||
#include "rtcp.hh"
|
||||
#include "socket.hh"
|
||||
#include "uvgrtp/rtcp.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "srtp/srtcp.hh"
|
||||
#include "srtp/srtp.hh"
|
||||
#include "formats/media.hh"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "multicast.hh"
|
||||
|
||||
#include "frame.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
|
||||
uvgrtp::multicast::multicast()
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
namespace uvgrtp {
|
||||
class connection;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "pkt_dispatch.hh"
|
||||
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
#include "random.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "poll.hh"
|
||||
|
||||
#include "multicast.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
|
||||
#include "rtp.hh"
|
||||
#include "srtp/base.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "random.hh"
|
||||
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "random.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
namespace uvgrtp {
|
||||
namespace random {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include "rtcp.hh"
|
||||
#include "uvgrtp/rtcp.hh"
|
||||
|
||||
#include "hostname.hh"
|
||||
#include "poll.hh"
|
||||
#include "debug.hh"
|
||||
#include "util.hh"
|
||||
#include "rtp.hh"
|
||||
#include "frame.hh"
|
||||
#include "srtp/srtcp.hh"
|
||||
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include "rtp.hh"
|
||||
|
||||
#include "frame.hh"
|
||||
#include "debug.hh"
|
||||
#include "random.hh"
|
||||
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "clock.hh"
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/clock.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
namespace uvgrtp {
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "runner.hh"
|
||||
#include "uvgrtp/runner.hh"
|
||||
|
||||
uvgrtp::runner::runner():
|
||||
active_(false), runner_(nullptr)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "session.hh"
|
||||
#include "uvgrtp/session.hh"
|
||||
|
||||
#include "media_stream.hh"
|
||||
#include "uvgrtp/media_stream.hh"
|
||||
#include "zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
|
||||
uvgrtp::session::session(std::string addr):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "socket.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "base.hh"
|
||||
|
||||
#include "crypto.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "srtcp.hh"
|
||||
|
||||
#include "crypto.hh"
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include "srtp.hh"
|
||||
|
||||
#include "base.hh"
|
||||
#include "crypto.hh"
|
||||
#include "debug.hh"
|
||||
#include "frame.hh"
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
#include "zrtp/dh_kxchng.hh"
|
||||
#include "zrtp/hello.hh"
|
||||
#include "zrtp/hello_ack.hh"
|
||||
#include "socket.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "crypto.hh"
|
||||
#include "random.hh"
|
||||
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "commit.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "debug.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "defines.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "confack.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "zrtp_receiver.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "confirm.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "defines.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
namespace uvgrtp {
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
#include "zrtp_receiver.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "defines.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
#include "zrtp_receiver.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "socket.hh"
|
||||
#include "frame.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
|
||||
#include <cstring>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "defines.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
#include "zrtp_receiver.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "defines.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
#include "zrtp_receiver.hh"
|
||||
|
||||
#include "../zrtp.hh"
|
||||
#include "crypto.hh"
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include "uvgrtp/crypto.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "defines.hh"
|
||||
#include "zrtp_message.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "zrtp_message.hh"
|
||||
|
||||
#include "frame.hh"
|
||||
#include "socket.hh"
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/socket.hh"
|
||||
|
||||
#include "debug.hh"
|
||||
#include "uvgrtp/debug.hh"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "defines.hh"
|
||||
#include "util.hh"
|
||||
#include "../zrtp.hh"
|
||||
#include "frame.hh"
|
||||
|
||||
#include "uvgrtp/frame.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
|
||||
namespace uvgrtp {
|
||||
|
@ -40,4 +41,4 @@ namespace uvgrtp {
|
|||
};
|
||||
|
||||
|
||||
namespace uvg_rtp = uvgrtp;
|
||||
namespace uvg_rtp = uvgrtp;
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
#include "hello.hh"
|
||||
#include "hello_ack.hh"
|
||||
|
||||
#include "socket.hh"
|
||||
#include "crypto.hh"
|
||||
#include "../poll.hh"
|
||||
#include "debug.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include "uvgrtp/socket.hh"
|
||||
#include "uvgrtp/crypto.hh"
|
||||
|
||||
#include "uvgrtp/debug.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "lib.hh"
|
||||
#include "uvgrtp/lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(VersionTests, version) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "lib.hh"
|
||||
#include "uvgrtp/lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "lib.hh"
|
||||
#include "uvgrtp/lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
constexpr char LOCAL_INTERFACE[] = "127.0.0.1";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "lib.hh"
|
||||
#include "uvgrtp/lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
constexpr uint16_t SEND_PORT = 9100;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "lib.hh"
|
||||
#include "uvgrtp/lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
|
|
22
uvgRTP.pro
22
uvgRTP.pro
|
@ -79,17 +79,17 @@ SOURCES += \
|
|||
src/srtp/srtcp.cc \
|
||||
|
||||
HEADERS += \
|
||||
include/clock.hh \
|
||||
include/crypto.hh \
|
||||
include/debug.hh \
|
||||
include/frame.hh \
|
||||
include/lib.hh \
|
||||
include/media_stream.hh \
|
||||
include/rtcp.hh \
|
||||
include/runner.hh \
|
||||
include/session.hh \
|
||||
include/socket.hh \
|
||||
include/util.hh \
|
||||
include/uvgrtp/clock.hh \
|
||||
include/uvgrtp/crypto.hh \
|
||||
include/uvgrtp/debug.hh \
|
||||
include/uvgrtp/frame.hh \
|
||||
include/uvgrtp/lib.hh \
|
||||
include/uvgrtp/media_stream.hh \
|
||||
include/uvgrtp/rtcp.hh \
|
||||
include/uvgrtp/runner.hh \
|
||||
include/uvgrtp/session.hh \
|
||||
include/uvgrtp/socket.hh \
|
||||
include/uvgrtp/util.hh \
|
||||
include/version.hh \
|
||||
src/dispatch.hh \
|
||||
src/holepuncher.hh \
|
||||
|
|
Loading…
Reference in New Issue