From 29a246a7334c0a298053991f37d22e19de936ad9 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 21 Feb 2024 14:12:23 +1100 Subject: Make the drain buffer very large, and move it into PSRAM the i2s handler and streambuffer metadata are both still in iram for good performance. otherwise, this seems to be enough to make gapless playback work. --- src/audio/audio_fsm.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src/audio/audio_fsm.cpp') diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index ba6e5ffe..0119855a 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -13,7 +13,9 @@ #include "audio_sink.hpp" #include "bluetooth_types.hpp" +#include "esp_heap_caps.h" #include "esp_log.h" +#include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "freertos/projdefs.h" @@ -192,20 +194,28 @@ void AudioState::react(const TogglePlayPause& ev) { namespace states { +// Two seconds of samples for two channels, at a representative sample rate. +constexpr size_t kDrainBufferSize = sizeof(sample::Sample) * 48000 * 4; +static StreamBufferHandle_t sDrainBuffer; + void Uninitialised::react(const system_fsm::BootComplete& ev) { sServices = ev.services; - constexpr size_t kDrainBufferSize = - drivers::kI2SBufferLengthFrames * sizeof(sample::Sample) * 2 * 8; ESP_LOGI(kTag, "allocating drain buffer, size %u KiB", kDrainBufferSize / 1024); - StreamBufferHandle_t stream = xStreamBufferCreateWithCaps( - kDrainBufferSize, sizeof(sample::Sample), MALLOC_CAP_DMA); + + auto meta = reinterpret_cast( + heap_caps_malloc(sizeof(StaticStreamBuffer_t), MALLOC_CAP_DMA)); + auto storage = reinterpret_cast( + heap_caps_malloc(kDrainBufferSize, MALLOC_CAP_SPIRAM)); + + sDrainBuffer = xStreamBufferCreateStatic( + kDrainBufferSize, sizeof(sample::Sample), storage, meta); sFileSource.reset( new FatfsAudioInput(sServices->tag_parser(), sServices->bg_worker())); - sI2SOutput.reset(new I2SAudioOutput(stream, sServices->gpios())); - sBtOutput.reset(new BluetoothAudioOutput(stream, sServices->bluetooth(), + sI2SOutput.reset(new I2SAudioOutput(sDrainBuffer, sServices->gpios())); + sBtOutput.reset(new BluetoothAudioOutput(sDrainBuffer, sServices->bluetooth(), sServices->bg_worker())); auto& nvs = sServices->nvs(); -- cgit v1.2.3 From 28651fa7e1d6a90af65d268e6515ed1d2e3b6037 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 21 Feb 2024 14:13:19 +1100 Subject: Wait for the sink buffer to drain before stopping playback --- src/audio/audio_fsm.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/audio/audio_fsm.cpp') diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index 0119855a..ea0315eb 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -366,6 +366,12 @@ void Playback::react(const internal::InputFileFinished& ev) { ESP_LOGI(kTag, "finished playing file"); sServices->track_queue().finish(); if (!sServices->track_queue().current()) { + for (int i = 0; i < 20; i++) { + if (xStreamBufferIsEmpty(sDrainBuffer)) { + break; + } + vTaskDelay(pdMS_TO_TICKS(200)); + } transit(); } } -- cgit v1.2.3