diff --git a/components/aes67_tx/aes67_tx.c b/components/aes67_tx/aes67_tx.c index bcd387d..4ff509f 100644 --- a/components/aes67_tx/aes67_tx.c +++ b/components/aes67_tx/aes67_tx.c @@ -22,6 +22,7 @@ #define MAX_LAG_NS 20000000 // more than 20 ms behind: resync instead of bursting #define TONE_HZ 1000 #define TONE_DBFS -18.0 +#define WAKE_MARGIN_US 20 // wake just after a packet's last sample is due static const char *TAG = "aes67_tx"; @@ -166,15 +167,23 @@ static int64_t samples_to_ns(int64_t s, int rate) } // 1 kHz tone, phase from the PTP sample index, so every sender's tone lines up. +// One period is rate / 1000 samples (48 at 48 kHz, 96 at 96 kHz): precomputed table. static void tone(int32_t *buf, int frames, int channels, int rate, int64_t s0) { - static float amp; - if (!amp) { - amp = (float)(pow(10.0, TONE_DBFS / 20.0) * 2147483647.0); - } + static int32_t table[96000 / TONE_HZ]; + static int table_rate; int period = rate / TONE_HZ; + if (table_rate != rate) { + double amp = pow(10.0, TONE_DBFS / 20.0) * 2147483647.0; + for (int i = 0; i < period; i++) { + table[i] = (int32_t)(amp * sin(2.0 * M_PI * i / period)); + } + table_rate = rate; + } + int ph = (int)(s0 % period); for (int i = 0; i < frames; i++) { - int32_t v = (int32_t)(amp * sinf(2.0f * (float)M_PI * (float)((s0 + i) % period) / (float)period)); + int32_t v = table[ph]; + ph = ph + 1 == period ? 0 : ph + 1; for (int ch = 0; ch < channels; ch++) { buf[i * channels + ch] = v; } @@ -216,8 +225,6 @@ static void tx_task(void *arg) next = 0; if (c.enabled) { fd = open_socket(&c); - // wake once per packet time; late wakes are caught up below - esp_timer_start_periodic(timer, (uint64_t)c.frames * 1000000ULL / c.rate); } } @@ -277,6 +284,13 @@ static void tx_task(void *arg) seq++; next += c.frames; } + // Wake when the next packet's last sample is due (PTP time), not on a free-running + // period, so each packet leaves right after it is complete. Re-read the clock: + // building and sending took time. + aes67_ptp_now_ns(&now); + int64_t wait_us = (samples_to_ns(next + c.frames, c.rate) - now) / 1000 + WAKE_MARGIN_US; + esp_timer_stop(timer); + esp_timer_start_once(timer, wait_us < 50 ? 50 : wait_us > 10000 ? 10000 : wait_us); } if (new_state != state) { state = new_state;