From 265049c5192cf0ce862c7db7b4745636afb6c17b Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 8 May 2024 16:03:03 +1000 Subject: Count samples going in and out of the drain buffer This is a more accurate way of knowing which track is playing when, and also simplifies a lot of fragile logic in audio_fsm --- src/drivers/i2s_dac.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src/drivers/i2s_dac.cpp') diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index a271fce0..e5efe198 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -5,6 +5,7 @@ */ #include "drivers/i2s_dac.hpp" +#include #include #include @@ -140,11 +141,10 @@ auto I2SDac::SetPaused(bool paused) -> void { } } -static volatile bool sSwapWords = false; +DRAM_ATTR static volatile bool sSwapWords = false; -auto I2SDac::Reconfigure(Channels ch, - BitsPerSample bps, - SampleRate rate) -> void { +auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) + -> void { std::lock_guard lock(configure_mutex_); if (i2s_active_) { @@ -217,6 +217,8 @@ auto I2SDac::WriteData(const std::span& data) -> void { } } +DRAM_ATTR static volatile uint32_t sSamplesRead = 0; + extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle, i2s_event_data_t* event, void* user_ctx) -> bool { @@ -235,6 +237,14 @@ extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle, size_t bytes_written = xStreamBufferReceiveFromISR(src, buf, event->size, &ret); + // Assume 16 bit samples. + size_t samples = bytes_written / 2; + if (UINT32_MAX - sSamplesRead < samples) { + sSamplesRead = samples - (UINT32_MAX - sSamplesRead); + } else { + sSamplesRead = sSamplesRead + samples; + } + // The ESP32's I2S peripheral has a different endianness to its processors. // ESP-IDF handles this difference for stereo channels, but not for mono // channels. We therefore sometimes need to swap each pair of words as they're @@ -276,6 +286,10 @@ auto I2SDac::SetSource(StreamBufferHandle_t buffer) -> void { } } +auto I2SDac::SamplesUsed() -> uint32_t { + return sSamplesRead; +} + auto I2SDac::set_channel(bool enabled) -> void { if (i2s_active_ == enabled) { return; -- cgit v1.2.3