| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /*
- * SPDX-FileCopyrightText: 2026 DatanoiseTV
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /*
- * RTP audio streaming engine.
- *
- * Handles RTP packet construction, parsing, transmission and reception
- * for AES67 audio streams. Manages per-stream jitter buffers allocated
- * in PSRAM when available.
- */
- #pragma once
- #include <stdint.h>
- #include <stdbool.h>
- #include "esp_err.h"
- #include "aes67_config.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* RTP header as defined in RFC 3550, packed for network wire format */
- typedef struct __attribute__((packed)) {
- uint8_t flags; /* V=2, P, X, CC */
- uint8_t pt; /* M bit + payload type */
- uint16_t seq; /* Sequence number (network byte order) */
- uint32_t timestamp; /* RTP timestamp (network byte order) */
- uint32_t ssrc; /* Synchronization source (network byte order) */
- } aes67_rtp_header_t;
- /* Stream direction */
- typedef enum {
- AES67_STREAM_SOURCE = 0, /* TX: capture audio, send RTP */
- AES67_STREAM_SINK = 1, /* RX: receive RTP, play audio */
- } aes67_stream_dir_t;
- /* Stream status flags (bitmask) */
- #define AES67_RTP_STATUS_SEQ_ERROR (1 << 0)
- #define AES67_RTP_STATUS_SSRC_ERROR (1 << 1)
- #define AES67_RTP_STATUS_PT_ERROR (1 << 2)
- #define AES67_RTP_STATUS_TIMESTAMP_ERR (1 << 3)
- #define AES67_RTP_STATUS_RECEIVING (1 << 4)
- #define AES67_RTP_STATUS_MUTED (1 << 5)
- #define AES67_RTP_STATUS_OVERFLOW (1 << 6)
- #define AES67_RTP_STATUS_UNDERFLOW (1 << 7)
- /* Configuration for a single RTP stream */
- typedef struct {
- aes67_stream_dir_t direction;
- uint32_t dest_ip; /* Multicast destination IP (network order) */
- uint16_t dest_port; /* Destination port (host order) */
- uint16_t src_port; /* Source port (host order) */
- uint8_t payload_type; /* RTP payload type (e.g. 98) */
- uint32_t ssrc; /* SSRC identifier */
- uint32_t sample_rate; /* Sample rate in Hz */
- uint8_t channels; /* Number of audio channels */
- uint8_t word_length; /* Bytes per sample (2, 3, or 4) */
- aes67_codec_t codec; /* Audio codec */
- uint16_t packet_time_us; /* Packet time in microseconds */
- uint32_t playout_delay_us; /* Playout delay for sinks */
- uint8_t dscp; /* DSCP marking */
- uint8_t ttl; /* Multicast TTL */
- /* Channel routing: maps RTP channel index to local audio channel */
- uint8_t routing[CONFIG_AES67_MAX_CHANNELS_PER_STREAM];
- } aes67_rtp_stream_config_t;
- /* Runtime stream status */
- typedef struct {
- uint32_t status_flags; /* Bitmask of AES67_RTP_STATUS_* */
- uint32_t packets_sent; /* Total packets transmitted */
- uint32_t packets_received; /* Total packets received */
- uint32_t packets_lost; /* Detected packet loss count */
- uint32_t packets_late; /* Packets arriving after playout */
- uint32_t seq_errors; /* Sequence discontinuity count */
- int32_t jitter_us; /* Estimated jitter in microseconds */
- uint32_t last_rtp_timestamp; /* Last RTP timestamp processed */
- uint16_t last_seq; /* Last sequence number */
- } aes67_rtp_stream_status_t;
- /* Opaque stream handle */
- typedef struct aes67_rtp_stream *aes67_rtp_stream_handle_t;
- /* Opaque RTP engine handle */
- typedef struct aes67_rtp_engine *aes67_rtp_engine_handle_t;
- /**
- * Initialize the RTP engine. Creates the network sockets and processing tasks.
- */
- esp_err_t aes67_rtp_engine_init(const aes67_net_config_t *net_config,
- bool use_psram,
- aes67_rtp_engine_handle_t *handle);
- /**
- * Start the RTP engine (begins packet processing).
- */
- esp_err_t aes67_rtp_engine_start(aes67_rtp_engine_handle_t handle);
- /**
- * Stop the RTP engine.
- */
- esp_err_t aes67_rtp_engine_stop(aes67_rtp_engine_handle_t handle);
- /**
- * Destroy the RTP engine and all streams.
- */
- esp_err_t aes67_rtp_engine_destroy(aes67_rtp_engine_handle_t handle);
- /**
- * Add an RTP stream (source or sink). Returns a stream handle.
- */
- esp_err_t aes67_rtp_stream_add(aes67_rtp_engine_handle_t engine,
- const aes67_rtp_stream_config_t *config,
- aes67_rtp_stream_handle_t *stream);
- /**
- * Remove an RTP stream.
- */
- esp_err_t aes67_rtp_stream_remove(aes67_rtp_engine_handle_t engine,
- aes67_rtp_stream_handle_t stream);
- /**
- * Get stream status.
- */
- esp_err_t aes67_rtp_stream_get_status(aes67_rtp_stream_handle_t stream,
- aes67_rtp_stream_status_t *status);
- /**
- * Write audio samples to a source stream's buffer (called by audio driver).
- * Samples are interleaved, in native byte order, at the stream's word length.
- *
- * @param stream Source stream handle
- * @param samples Pointer to interleaved sample data
- * @param frame_count Number of audio frames (one sample per channel = one frame)
- * @return ESP_OK on success
- */
- esp_err_t aes67_rtp_source_write(aes67_rtp_stream_handle_t stream,
- const void *samples, uint32_t frame_count);
- /**
- * Read audio samples from a sink stream's jitter buffer (called by audio driver).
- * Returns silence if the jitter buffer is empty or the stream is muted.
- *
- * @param stream Sink stream handle
- * @param samples Output buffer for interleaved sample data
- * @param frame_count Number of frames to read
- * @return ESP_OK on success, ESP_ERR_NOT_FOUND if no data available
- */
- esp_err_t aes67_rtp_sink_read(aes67_rtp_stream_handle_t stream,
- void *samples, uint32_t frame_count);
- /**
- * Called by the audio frame timer (TIC) to trigger RTP packet transmission
- * for all active source streams.
- */
- esp_err_t aes67_rtp_engine_process_tx(aes67_rtp_engine_handle_t handle,
- uint32_t rtp_timestamp);
- /**
- * Get the stream buffer used for RTP RX -> playback decoupling.
- */
- #include "freertos/stream_buffer.h"
- StreamBufferHandle_t aes67_rtp_engine_get_stream_buf(aes67_rtp_engine_handle_t handle);
- /**
- * Set the task to notify when new sink data arrives.
- */
- #include "freertos/task.h"
- void aes67_rtp_engine_set_notify_task(aes67_rtp_engine_handle_t handle,
- TaskHandle_t task);
- /**
- * Enable/disable direct I2S playback from the RTP RX path.
- */
- void aes67_rtp_engine_set_playback(aes67_rtp_engine_handle_t handle,
- void *audio_handle);
- /**
- * Get available frames in a sink stream's jitter buffer.
- */
- uint32_t aes67_rtp_sink_available(aes67_rtp_stream_handle_t stream);
- #ifdef __cplusplus
- }
- #endif
|