| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- /*
- * SPDX-FileCopyrightText: 2026 DatanoiseTV
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /*
- * AES67 configuration structures.
- *
- * Kconfig provides compile-time defaults; these structs allow runtime
- * override before node initialization.
- *
- * Key design: all buffer sizes and frame counts are COMPUTED from the
- * base audio parameters (sample_rate, channels, word_length, packet_time_us)
- * via aes67_stream_params_compute(). No hardcoded 192, 2, 48000, etc.
- */
- #pragma once
- #include <stdint.h>
- #include <stdbool.h>
- #include "esp_eth.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* ---- Version ---- */
- #define AES67_VERSION_MAJOR 2
- #define AES67_VERSION_MINOR 2
- #define AES67_VERSION_PATCH 0
- /* ---- Limits ---- */
- #define AES67_MAX_CHANNELS_PER_STREAM 8
- #define AES67_MAX_TIC_FRAMES 1024
- #define AES67_MIN_TIC_FRAMES 48
- #define AES67_RTP_HEADER_SIZE 12
- #define AES67_MAX_WORD_LENGTH 4 /* AM824/L32 = 4 bytes */
- /* ---- Enums ---- */
- /* Audio codec identifiers matching AES67/RAVENNA conventions */
- typedef enum {
- AES67_CODEC_L16 = 0, /* 16-bit linear PCM, word_length=2 */
- AES67_CODEC_L24, /* 24-bit linear PCM, word_length=3 */
- AES67_CODEC_L32, /* 32-bit linear PCM, word_length=4 */
- AES67_CODEC_AM824, /* IEC 61937 / AM824, word_length=4 */
- } aes67_codec_t;
- /* Output mode for received audio data */
- typedef enum {
- AES67_OUTPUT_I2S = 0, /* Direct I2S output (default) */
- AES67_OUTPUT_STREAM_BUFFER, /* FreeRTOS StreamBuffer for app processing */
- AES67_OUTPUT_CALLBACK, /* User callback per packet */
- } aes67_output_mode_t;
- /* Callback for received audio data (when output_mode == AES67_OUTPUT_CALLBACK) */
- typedef void (*aes67_audio_data_cb_t)(const int32_t *samples,
- uint32_t frame_count,
- uint8_t channels,
- uint8_t word_length,
- uint32_t sample_rate,
- void *user_data);
- /* ---- Stream Parameters (computed, not configured) ---- */
- /*
- * Derived parameters computed from the base audio config.
- * Use aes67_stream_params_compute() to populate.
- * These replace all hardcoded 192, 768, 1536, etc.
- */
- typedef struct {
- /* From config */
- uint32_t sample_rate;
- uint8_t channels;
- uint8_t word_length; /* Bytes per sample on the wire (2/3/4) */
- uint16_t packet_time_us;
- /* Computed */
- uint32_t samples_per_packet; /* Frames per RTP packet (e.g., 48, 192) */
- uint32_t frame_bytes_wire; /* Bytes per frame on wire: channels * word_length */
- uint32_t frame_bytes_native; /* Bytes per frame in memory: channels * 4 (int32) */
- uint32_t packet_payload_size; /* RTP payload bytes: spp * frame_bytes_wire */
- uint32_t packet_native_size; /* Converted packet bytes: spp * frame_bytes_native */
- uint32_t max_packet_payload; /* Max RTP payload: MAX_TIC_FRAMES * frame_bytes_wire */
- } aes67_stream_params_t;
- /* Compute derived parameters from base config */
- static inline void aes67_stream_params_compute(aes67_stream_params_t *p,
- uint32_t sample_rate,
- uint8_t channels,
- uint8_t word_length,
- uint16_t packet_time_us)
- {
- p->sample_rate = sample_rate;
- p->channels = channels;
- p->word_length = word_length;
- p->packet_time_us = packet_time_us;
- p->samples_per_packet = (sample_rate * (uint32_t)packet_time_us) / 1000000;
- if (p->samples_per_packet == 0) p->samples_per_packet = 48;
- if (p->samples_per_packet > AES67_MAX_TIC_FRAMES) {
- p->samples_per_packet = AES67_MAX_TIC_FRAMES;
- }
- p->frame_bytes_wire = (uint32_t)channels * word_length;
- p->frame_bytes_native = (uint32_t)channels * sizeof(int32_t);
- p->packet_payload_size = p->samples_per_packet * p->frame_bytes_wire;
- p->packet_native_size = p->samples_per_packet * p->frame_bytes_native;
- p->max_packet_payload = AES67_MAX_TIC_FRAMES * p->frame_bytes_wire;
- }
- /* Get word_length from codec enum */
- static inline uint8_t aes67_codec_word_length(aes67_codec_t codec)
- {
- switch (codec) {
- case AES67_CODEC_L16: return 2;
- case AES67_CODEC_L24: return 3;
- case AES67_CODEC_L32: return 4;
- case AES67_CODEC_AM824: return 4;
- default: return 3;
- }
- }
- /* Get codec from word_length */
- static inline aes67_codec_t aes67_word_length_codec(uint8_t wl)
- {
- switch (wl) {
- case 2: return AES67_CODEC_L16;
- case 3: return AES67_CODEC_L24;
- case 4: return AES67_CODEC_L32;
- default: return AES67_CODEC_L24;
- }
- }
- /* ---- Configuration Structs ---- */
- /* Network configuration */
- typedef struct {
- char interface_name[16]; /* Ethernet interface, e.g. "ETH_0" */
- esp_eth_handle_t eth_handle; /* Ethernet driver handle */
- char rtp_mcast_base[16]; /* Base multicast address for RTP */
- uint16_t rtp_port; /* RTP port (default 5004) */
- uint8_t ttl; /* Multicast TTL */
- uint8_t dscp; /* DSCP for QoS (default 46 = EF) */
- } aes67_net_config_t;
- /* PTP configuration */
- typedef struct {
- uint8_t domain; /* PTP domain 0-127 */
- uint8_t dscp; /* DSCP for PTP packets */
- bool prefer_grandmaster; /* Become GM if no other master found */
- } aes67_ptp_config_t;
- /* Audio configuration */
- typedef struct {
- uint32_t sample_rate; /* Sample rate in Hz (44100 or 48000) */
- uint8_t word_length; /* Bytes per sample (2, 3, or 4) */
- uint16_t packet_time_us; /* Packet time in microseconds */
- uint8_t channels; /* Number of audio channels (1-8) */
- aes67_codec_t codec; /* Audio codec */
- } aes67_audio_config_t;
- /* I2S pin configuration */
- typedef struct {
- int mck_gpio;
- int bck_gpio;
- int ws_gpio;
- int dout_gpio;
- int din_gpio;
- } aes67_i2s_pins_t;
- /* Top-level node configuration */
- typedef struct {
- char node_name[64]; /* Node name for SDP/mDNS */
- aes67_net_config_t net;
- aes67_ptp_config_t ptp;
- aes67_audio_config_t audio;
- aes67_i2s_pins_t i2s_pins;
- uint16_t jitter_buffer_ms; /* Jitter buffer depth in ms */
- uint16_t ring_buffer_ms; /* Audio ring buffer size in ms */
- bool use_psram; /* Allocate large buffers in PSRAM */
- bool sap_enabled; /* Enable SAP announcements */
- bool mdns_enabled; /* Enable mDNS advertisement */
- /* Output routing */
- aes67_output_mode_t output_mode; /* How to deliver received audio */
- aes67_audio_data_cb_t audio_cb; /* Callback (when mode == CALLBACK) */
- void *audio_cb_user_data; /* User data for callback */
- } aes67_config_t;
- /* Initialize a config struct with Kconfig defaults */
- #define AES67_CONFIG_DEFAULT() { \
- .node_name = CONFIG_AES67_NODE_NAME, \
- .net = { \
- .interface_name = "ETH_0", \
- .eth_handle = NULL, \
- .rtp_mcast_base = CONFIG_AES67_RTP_MCAST_BASE, \
- .rtp_port = CONFIG_AES67_RTP_PORT, \
- .ttl = 64, \
- .dscp = 46, \
- }, \
- .ptp = { \
- .domain = CONFIG_AES67_PTP_DOMAIN, \
- .dscp = 46, \
- .prefer_grandmaster = true, \
- }, \
- .audio = { \
- .sample_rate = CONFIG_AES67_DEFAULT_SAMPLE_RATE, \
- .word_length = CONFIG_AES67_DEFAULT_WORD_LENGTH, \
- .packet_time_us = CONFIG_AES67_DEFAULT_PACKET_TIME_US, \
- .channels = CONFIG_AES67_DEFAULT_CHANNELS, \
- .codec = AES67_CODEC_L24, \
- }, \
- .i2s_pins = { \
- .mck_gpio = CONFIG_AES67_I2S_MCK_GPIO, \
- .bck_gpio = CONFIG_AES67_I2S_BCK_GPIO, \
- .ws_gpio = CONFIG_AES67_I2S_WS_GPIO, \
- .dout_gpio = CONFIG_AES67_I2S_DOUT_GPIO, \
- .din_gpio = CONFIG_AES67_I2S_DIN_GPIO, \
- }, \
- .jitter_buffer_ms = CONFIG_AES67_JITTER_BUFFER_MS, \
- .ring_buffer_ms = CONFIG_AES67_AUDIO_RING_BUFFER_MS, \
- .use_psram = true, \
- .sap_enabled = true, \
- .mdns_enabled = true, \
- .output_mode = AES67_OUTPUT_I2S, \
- .audio_cb = NULL, \
- .audio_cb_user_data = NULL, \
- }
- #ifdef __cplusplus
- }
- #endif
|