#include "audio_ring.h" #include #include "esp_heap_caps.h" static int32_t *s_buf; static size_t s_cap; // frames static int s_ch; // Monotonic frame counters; level = wr - rd. Written by one side each (acquire/release). static uint32_t s_wr, s_rd; esp_err_t audio_ring_init(size_t capacity_frames, int channels) { s_buf = heap_caps_malloc(capacity_frames * channels * sizeof(int32_t), MALLOC_CAP_SPIRAM); if (!s_buf) { return ESP_ERR_NO_MEM; } s_cap = capacity_frames; s_ch = channels; return ESP_OK; } size_t audio_ring_level(void) { return __atomic_load_n(&s_wr, __ATOMIC_ACQUIRE) - __atomic_load_n(&s_rd, __ATOMIC_ACQUIRE); } size_t audio_ring_space(void) { return s_cap - audio_ring_level(); } // Copy n frames between the ring (starting at frame index pos) and a linear buffer. static void copy(int32_t *ring_to_lin, const int32_t *lin_to_ring, uint32_t pos, size_t n) { size_t start = pos % s_cap; size_t first = n < s_cap - start ? n : s_cap - start; size_t fb = first * s_ch * sizeof(int32_t), rb = (n - first) * s_ch * sizeof(int32_t); if (ring_to_lin) { memcpy(ring_to_lin, s_buf + start * s_ch, fb); memcpy(ring_to_lin + first * s_ch, s_buf, rb); } else { memcpy(s_buf + start * s_ch, lin_to_ring, fb); memcpy(s_buf, lin_to_ring + first * s_ch, rb); } } size_t audio_ring_write(const int32_t *frames, size_t n) { uint32_t wr = __atomic_load_n(&s_wr, __ATOMIC_RELAXED); size_t space = s_cap - (wr - __atomic_load_n(&s_rd, __ATOMIC_ACQUIRE)); n = n < space ? n : space; if (n) { copy(NULL, frames, wr, n); __atomic_store_n(&s_wr, wr + n, __ATOMIC_RELEASE); } return n; } size_t audio_ring_read(int32_t *frames, size_t n) { uint32_t rd = __atomic_load_n(&s_rd, __ATOMIC_RELAXED); size_t level = __atomic_load_n(&s_wr, __ATOMIC_ACQUIRE) - rd; n = n < level ? n : level; if (n) { copy(frames, NULL, rd, n); __atomic_store_n(&s_rd, rd + n, __ATOMIC_RELEASE); } return n; } uint32_t audio_ring_written(void) { return __atomic_load_n(&s_wr, __ATOMIC_ACQUIRE); } uint32_t audio_ring_read_pos(void) { return __atomic_load_n(&s_rd, __ATOMIC_ACQUIRE); } void audio_ring_flush(void) { __atomic_store_n(&s_rd, __atomic_load_n(&s_wr, __ATOMIC_ACQUIRE), __ATOMIC_RELEASE); }