Step 4.2: PTP-paced AES67 RTP sender with 1 kHz test tone

- aes67_tx: TX task woken by an esp_timer every packet time; sends every
  packet whose last sample is in the past (PTP time), RTP ts =
  (sample index from PTP + clk_offset) mod 2^32, packets aligned to
  multiples of the packet size. Sends only while PTP is locked; resyncs
  on lock, clock step or > 20 ms lag. L24/L16 big-endian, TTL/DSCP/
  multicast IF from config; a config save restarts TX.
- Built-in 1 kHz tone at -18 dBFS, phase from the PTP sample index;
  aes67_tx_set_source() pull callback for later sources (underruns
  counted, padded with silence). status: tx_packets, underruns.
- Verified with a receiver script on the PC: 1 ms L24 stereo 1000/s,
  0 gaps, ts step 48, tone -18.00 dBFS within 1.2 LSB of the ideal
  PTP-phased sine; also L16 mono 0.333 ms, 0.125 ms (8000/s) and 4 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 06:43:12 +10:00
parent 3d05768f00
commit bae6a8a2f9
4 changed files with 249 additions and 6 deletions
+12 -1
View File
@@ -2,7 +2,18 @@
// Core component: must not depend on main/ (project code).
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
// Registers the "aes67" config group and the TX status fields. (Sender itself: step 4.)
// Audio source: fill buf with frames x channels interleaved samples (full scale = INT32_MAX).
// Return the number of frames delivered; fewer than asked counts as an underrun (padded with silence).
typedef size_t (*aes67_tx_read_cb_t)(int32_t *buf, size_t frames);
// Registers the "aes67" config group and the TX status fields.
esp_err_t aes67_tx_init(void);
// Start the sender task. Sends while PTP is locked and aes67.enabled is set.
esp_err_t aes67_tx_start(void);
// Set the audio source. NULL = built-in 1 kHz test tone at -18 dBFS, phase-locked to PTP time.
void aes67_tx_set_source(aes67_tx_read_cb_t read);