RAVENNAKIT
Loading...
Searching...
No Matches
rtp_audio_receiver.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2/*
3 * Project: RAVENNAKIT (RAVENNA / AES67 / ST2110-30 SDK)
4 * Copyright (c) 2024-2025 Sound on Digital
5 *
6 * This file is part of RAVENNAKIT.
7 *
8 * RAVENNAKIT is dual-licensed:
9 * 1) Under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version (the "AGPL License"); and
12 * 2) Under a commercial license from Sound on Digital, for customers who
13 * cannot (or do not wish to) comply with the AGPL License terms.
14 *
15 * If you obtained this file under the AGPL License, you may redistribute it
16 * and/or modify it under the terms of the AGPL License. See the LICENSE
17 * file in the project root for details.
18 *
19 * For commercial licensing, support, and other inquiries, please visit:
20 *
21 * https://ravennakit.com
22 *
23 */
24
25#pragma once
26
27#include "rtp_filter.hpp"
28#include "rtp_packet_stats.hpp"
29#include "rtp_ringbuffer.hpp"
30#include "rtp_session.hpp"
40
41#include <boost/asio.hpp>
42#include <boost/container/static_vector.hpp>
43#include <boost/lockfree/spsc_value.hpp>
44
45#ifndef RAV_MAX_NUM_READERS
46 #define RAV_MAX_NUM_READERS 16
47#endif
48
49namespace rav::rtp {
50
53 static constexpr auto k_max_num_readers = RAV_MAX_NUM_READERS;
54
56 static constexpr auto k_max_num_redundant_sessions = 2; // How many redundant paths
57
59 static constexpr uint64_t k_receive_timeout_ms = 1000;
60
64 static constexpr uint32_t k_buffer_size_ms = 200;
65
66 using ArrayOfAddresses = std::array<ip_address_v4, k_max_num_redundant_sessions>;
67
68 struct StreamInfo {
71 uint16_t packet_time_frames {};
72
73 [[nodiscard]] auto tie() const {
74 return std::tie(session, filter, packet_time_frames);
75 }
76
77 friend bool operator==(const StreamInfo& lhs, const StreamInfo& rhs) {
78 return lhs.tie() == rhs.tie();
79 }
80
81 friend bool operator!=(const StreamInfo& lhs, const StreamInfo& rhs) {
82 return lhs.tie() != rhs.tie();
83 }
84
85 [[nodiscard]] bool is_valid() const {
86 return session.valid() && packet_time_frames > 0;
87 }
88 };
89
92 std::array<StreamInfo, k_max_num_redundant_sessions> streams;
93
94 [[nodiscard]] auto tie() const {
95 return std::tie(audio_format, streams);
96 }
97
98 friend bool operator==(const ReaderParameters& lhs, const ReaderParameters& rhs) {
99 return lhs.tie() == rhs.tie();
100 }
101
102 friend bool operator!=(const ReaderParameters& lhs, const ReaderParameters& rhs) {
103 return lhs.tie() != rhs.tie();
104 }
105
106 [[nodiscard]] bool is_valid() const {
107 if (!audio_format.is_valid()) {
108 return false;
109 }
110 for (auto& stream : streams) {
111 if (stream.is_valid()) {
112 return true; // At least one stream needs to be valid.
113 }
114 }
115 return false;
116 }
117 };
118
130
131 explicit AudioReceiver(boost::asio::io_context& io_context);
133
142 [[nodiscard]] bool add_reader(Id id, const ReaderParameters& parameters, const ArrayOfAddresses& interfaces);
143
150 [[nodiscard]] bool remove_reader(Id id);
151
156 [[nodiscard]] bool set_interfaces(const ArrayOfAddresses& interfaces);
157
163
180 [[nodiscard]] std::optional<uint32_t> read_data_realtime(
181 Id id, uint8_t* buffer, size_t buffer_size, std::optional<uint32_t> at_timestamp, std::optional<uint32_t> require_delay
182 );
183
199 [[nodiscard]] std::optional<uint32_t> read_audio_data_realtime(
200 Id id, AudioBufferView<float>& output_buffer, std::optional<uint32_t> at_timestamp, std::optional<uint32_t> require_delay
201 );
202
208 std::optional<PacketStats::Counters> get_packet_stats(Id reader_id, size_t stream_index);
209
215 [[nodiscard]] std::optional<StreamState> get_stream_state(Id reader_id, size_t stream_index) const;
216
218 explicit SocketWithContext(boost::asio::io_context& io_context) : socket(io_context) {}
219
222 uint16_t port {};
223 };
224
226 uint32_t timestamp;
227 uint16_t seq;
228 uint16_t data_len;
229 uint64_t recv_time;
230 std::array<uint8_t, aes67::constants::k_max_payload> payload;
231 };
232
248
252 struct Reader {
256 std::array<StreamContext, k_max_num_redundant_sessions> streams;
257
258 // Audio thread
260 std::vector<uint8_t> read_audio_data_buffer;
261 std::optional<WrappingUint32> most_recent_ts; // ts of the latest received data
263 };
264
267
270
272
274
275 boost::container::static_vector<SocketWithContext, k_max_num_sessions> sockets;
276 boost::container::static_vector<Reader, k_max_num_readers> readers;
277
279};
280
284[[nodiscard]] const char* to_string(AudioReceiver::StreamState state);
285
286} // namespace rav::rtp
A lock-free (and sometimes wait-free) reader writer lock.
A non-owning view of a non-interleaved audio buffer.
A classic FIFO buffer implementation with different strategies F.
A class which represents a unique identifier.
Definition id.hpp:38
A simple callback function wrapper that can be used to store and call a function with a specific sign...
Implements logic for filtering RTP packets.
A class that collects statistics about RTP packets.
A buffer which operates on bytes, unaware of its contents.
const char * to_string(AudioReceiver::StreamState state)
WrappingUint< uint32_t > WrappingUint32
32-bit wrapping unsigned integer.
boost::asio::ip::udp::socket udp_socket
WrappingUint< uint64_t > WrappingUint64
64-bit wrapping unsigned integer.
boost::asio::ip::address_v4 ip_address_v4
#define RAV_MAX_NUM_READERS
Keeps track of an ema with outliers filtered out and a max deviation.
std::array< uint8_t, aes67::constants::k_max_payload > payload
Holds the structures to receive incoming data from redundant sources into a single buffer.
std::vector< uint8_t > read_audio_data_buffer
std::optional< WrappingUint32 > most_recent_ts
std::array< StreamContext, k_max_num_redundant_sessions > streams
friend bool operator!=(const ReaderParameters &lhs, const ReaderParameters &rhs)
friend bool operator==(const ReaderParameters &lhs, const ReaderParameters &rhs)
std::array< StreamInfo, k_max_num_redundant_sessions > streams
SocketWithContext(boost::asio::io_context &io_context)
FifoBuffer< uint16_t, Fifo::Spsc > packets_too_old
boost::lockfree::spsc_value< PacketStats::Counters, boost::lockfree::allow_multiple_reads< true > > packet_stats_counters
std::optional< WrappingUint32 > rtp_ts
FifoBuffer< PacketBuffer, Fifo::Spsc > packets
friend bool operator!=(const StreamInfo &lhs, const StreamInfo &rhs)
friend bool operator==(const StreamInfo &lhs, const StreamInfo &rhs)
static constexpr auto k_max_num_redundant_sessions
The maximum number of redundant sessions per reader (redundant paths).
std::optional< PacketStats::Counters > get_packet_stats(Id reader_id, size_t stream_index)
boost::container::static_vector< SocketWithContext, k_max_num_sessions > sockets
bool remove_reader(Id id)
Removes the reader with given id, if it exists.
SafeFunction< bool(udp_socket &, ip_address_v4, ip_address_v4)> join_multicast_group
Function for joining a multicast group. Can be overridden to alter behaviour. Used for unit testing.
SafeFunction< bool(udp_socket &, ip_address_v4, ip_address_v4)> leave_multicast_group
Function for leaving a multicast group. Can be overridden to alter behaviour. Used for unit testing.
static constexpr auto k_max_num_readers
The maximum number of readers.
static constexpr uint32_t k_buffer_size_ms
The length of the receiver buffer in milliseconds.
std::optional< uint32_t > read_data_realtime(Id id, uint8_t *buffer, size_t buffer_size, std::optional< uint32_t > at_timestamp, std::optional< uint32_t > require_delay)
Reads data from the buffer at the given timestamp.
std::optional< StreamState > get_stream_state(Id reader_id, size_t stream_index) const
StreamState
The state of a reader.
@ receiving
Packets are being received and consumed.
@ no_consumer
Packets are being received, but they are not consumed.
@ inactive
The stream is inactive because no packets have been received for a while.
std::array< ip_address_v4, k_max_num_redundant_sessions > ArrayOfAddresses
ptp::Instance::Subscriber ptp_instance_subscriber
bool add_reader(Id id, const ReaderParameters &parameters, const ArrayOfAddresses &interfaces)
Adds a reader to the receiver.
static constexpr uint64_t k_receive_timeout_ms
The number of milliseconds after which a stream is considered inactive.
void read_incoming_packets()
Call this to read incoming packets and place the data inside a fifo for consumption.
bool set_interfaces(const ArrayOfAddresses &interfaces)
Sets the interfaces on all readers, leaving and joining multicast groups where necessary.
static constexpr auto k_max_num_sessions
AudioReceiver(boost::asio::io_context &io_context)
std::optional< uint32_t > read_audio_data_realtime(Id id, AudioBufferView< float > &output_buffer, std::optional< uint32_t > at_timestamp, std::optional< uint32_t > require_delay)
Reads the data from the receiver with the given id.
boost::container::static_vector< Reader, k_max_num_readers > readers