From 4c88fcc4a57b1fae7b6edaf42034945d5ac24a89 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Fri, 20 Jan 2023 09:48:29 +1100 Subject: [PATCH] fix build issues with new pipeline --- src/audio/CMakeLists.txt | 2 +- src/audio/audio_decoder.cpp | 2 +- src/audio/audio_element_handle.cpp | 79 ++++++++++++++++++++++ src/audio/fatfs_audio_input.cpp | 8 ++- src/audio/include/audio_decoder.hpp | 2 +- src/audio/include/audio_element_handle.hpp | 41 +++++++++++ src/audio/include/fatfs_audio_input.hpp | 2 +- src/drivers/display.cpp | 1 - src/drivers/include/gpio_expander.hpp | 2 +- src/main/main.cpp | 17 +++-- 10 files changed, 141 insertions(+), 15 deletions(-) create mode 100644 src/audio/audio_element_handle.cpp create mode 100644 src/audio/include/audio_element_handle.hpp diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index cf58f00c..4986a7da 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -1,7 +1,7 @@ idf_component_register( SRCS "audio_decoder.cpp" "audio_task.cpp" "chunk.cpp" "fatfs_audio_input.cpp" "stream_info.cpp" "stream_message.cpp" "i2s_audio_output.cpp" - "stream_buffer.cpp" "audio_playback.cpp" + "stream_buffer.cpp" "audio_playback.cpp" "audio_element_handle.cpp" INCLUDE_DIRS "include" REQUIRES "codecs" "drivers" "cbor" "result" "tasks" "span") diff --git a/src/audio/audio_decoder.cpp b/src/audio/audio_decoder.cpp index 88ddc323..0b3d9878 100644 --- a/src/audio/audio_decoder.cpp +++ b/src/audio/audio_decoder.cpp @@ -58,7 +58,7 @@ auto AudioDecoder::ProcessChunk(const cpp::span& chunk) bool needs_more_input = false; std::optional error = std::nullopt; while (1) { - ChunkWriteResult res = chunk_writer_.WriteChunkToStream( + ChunkWriteResult res = chunk_writer_->WriteChunkToStream( [&](cpp::span buffer) -> std::size_t { std::size_t bytes_written = 0; // Continue filling up the output buffer so long as we have samples diff --git a/src/audio/audio_element_handle.cpp b/src/audio/audio_element_handle.cpp new file mode 100644 index 00000000..4b746db3 --- /dev/null +++ b/src/audio/audio_element_handle.cpp @@ -0,0 +1,79 @@ +#include "audio_element_handle.hpp" +#include "audio_element.hpp" +#include "freertos/projdefs.h" + +namespace audio { + +AudioElementHandle::AudioElementHandle(std::unique_ptr task, + std::shared_ptr element) + : task_(std::move(task)), element_(std::move(element)) {} + +AudioElementHandle::~AudioElementHandle() { + Quit(); +} + +auto AudioElementHandle::CurrentState() -> ElementState { + return element_->ElementState(); +} + +auto AudioElementHandle::PlayPause(enum PlayPause state) -> void { + ElementState s = CurrentState(); + if (state == PLAY && s == STATE_PAUSE) { + // Ensure we actually finished any previous pause command. + // TODO: really? + PauseSync(); + SetStateAndWakeUp(STATE_RUN); + return; + } + if (state == PAUSE && s == STATE_RUN) { + element_->ElementState(STATE_PAUSE); + SetStateAndWakeUp(STATE_PAUSE); + return; + } +} + +auto AudioElementHandle::Quit() -> void { + SetStateAndWakeUp(STATE_QUIT); +} + +auto AudioElementHandle::PauseSync() -> void { + PlayPause(PAUSE); + MonitorUtilState(eSuspended); +} + +auto AudioElementHandle::QuitSync() -> void { + Quit(); + MonitorUtilState(eDeleted); +} + +auto AudioElementHandle::MonitorUtilState(eTaskState desired) -> void { + while (eTaskGetState(task_.get()) != desired) { + WakeUpTask(); + vTaskDelay(pdMS_TO_TICKS(1)); + } +} + +auto AudioElementHandle::SetStateAndWakeUp(ElementState state) -> void { + element_->ElementState(state); + WakeUpTask(); +} + +auto AudioElementHandle::WakeUpTask() -> void { + // TODO: various races where the task isn't blocked yet, but there is a block + // between now and its next element state check. Also think about chunk blocks + // nested in element bodies. + // Maybe we need a big mutex or semaphore somewhere in here. + switch (eTaskGetState(task_.get())) { + case eBlocked: + // TODO: when is this safe? + xTaskAbortDelay(task_.get()); + break; + case eSuspended: + vTaskResume(task_.get()); + break; + default: + return; + } +} + +} // namespace audio diff --git a/src/audio/fatfs_audio_input.cpp b/src/audio/fatfs_audio_input.cpp index bc5be42a..3e501154 100644 --- a/src/audio/fatfs_audio_input.cpp +++ b/src/audio/fatfs_audio_input.cpp @@ -9,6 +9,7 @@ #include "audio_element.hpp" #include "chunk.hpp" +#include "stream_buffer.hpp" #include "stream_message.hpp" static const char* kTag = "SRC"; @@ -29,7 +30,10 @@ FatfsAudioInput::FatfsAudioInput(std::shared_ptr storage) file_buffer_read_pos_(file_buffer_.begin()), file_buffer_write_pos_(file_buffer_.begin()), current_file_(), - is_file_open_(false) {} + is_file_open_(false), + chunk_writer_(nullptr) { + // TODO: create our chunk writer whenever the output buffer changes. +} FatfsAudioInput::~FatfsAudioInput() { free(raw_file_buffer_); @@ -127,7 +131,7 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result { // Now stream data into the output buffer until it's full. while (1) { - ChunkWriteResult result = chunk_writer_.WriteChunkToStream( + ChunkWriteResult result = chunk_writer_->WriteChunkToStream( [&](cpp::span d) { return SendChunk(d); }, kServiceInterval); switch (result) { diff --git a/src/audio/include/audio_decoder.hpp b/src/audio/include/audio_decoder.hpp index 9c0626db..0a2df76d 100644 --- a/src/audio/include/audio_decoder.hpp +++ b/src/audio/include/audio_decoder.hpp @@ -43,7 +43,7 @@ class AudioDecoder : public IAudioElement { std::unique_ptr current_codec_; std::optional stream_info_; - ChunkWriter chunk_writer_; + std::unique_ptr chunk_writer_; }; } // namespace audio diff --git a/src/audio/include/audio_element_handle.hpp b/src/audio/include/audio_element_handle.hpp new file mode 100644 index 00000000..adb26baa --- /dev/null +++ b/src/audio/include/audio_element_handle.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include "audio_element.hpp" + +namespace audio { + +class AudioElementHandle { + public: + AudioElementHandle(std::unique_ptr task, + std::shared_ptr element); + ~AudioElementHandle(); + + auto CurrentState() -> ElementState; + + // TODO: think about this contract. Would it ever make sense to pause and + // then walk away? Things could keep running for a whole loop if data comes + // through, so probably not? + enum PlayPause { + PLAY, + PAUSE, + }; + auto PlayPause(PlayPause state) -> void; + auto Quit() -> void; + + auto PauseSync() -> void; + auto QuitSync() -> void; + + AudioElementHandle(const AudioElementHandle&) = delete; + AudioElementHandle& operator=(const AudioElementHandle&) = delete; + + private: + std::unique_ptr task_; + std::shared_ptr element_; + + auto MonitorUtilState(eTaskState desired) -> void; + auto SetStateAndWakeUp(ElementState state) -> void; + auto WakeUpTask() -> void; +}; + +} // namespace audio diff --git a/src/audio/include/fatfs_audio_input.hpp b/src/audio/include/fatfs_audio_input.hpp index 040b2b54..f3704f1d 100644 --- a/src/audio/include/fatfs_audio_input.hpp +++ b/src/audio/include/fatfs_audio_input.hpp @@ -47,7 +47,7 @@ class FatfsAudioInput : public IAudioElement { FIL current_file_; bool is_file_open_; - ChunkWriter chunk_writer_; + std::unique_ptr chunk_writer_; }; } // namespace audio diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp index ba5d08d3..8aaca4a4 100644 --- a/src/drivers/display.cpp +++ b/src/drivers/display.cpp @@ -74,7 +74,6 @@ static void IRAM_ATTR post_cb(spi_transaction_t* transaction) { auto Display::create(GpioExpander* expander, const displays::InitialisationData& init_data) -> cpp::result, Error> { - expander->with( [&](auto& gpio) { gpio.set_pin(GpioExpander::DISPLAY_LED, 1); }); diff --git a/src/drivers/include/gpio_expander.hpp b/src/drivers/include/gpio_expander.hpp index 1faf0f88..8875e954 100644 --- a/src/drivers/include/gpio_expander.hpp +++ b/src/drivers/include/gpio_expander.hpp @@ -110,7 +110,7 @@ class GpioExpander { // Port B PHONE_DETECT = 8, // Active-high input - //UNUSED = 9, + // UNUSED = 9, VOL_UP = 10, VOL_DOWN = 11, LOCK = 12, diff --git a/src/main/main.cpp b/src/main/main.cpp index 623d948d..deef29e1 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -98,12 +98,12 @@ extern "C" void app_main(void) { drivers::GpioExpander* expander = new drivers::GpioExpander(); ESP_LOGI(TAG, "Enable power rails for development"); - expander->with( - [&](auto& gpio) { - gpio.set_pin(drivers::GpioExpander::AUDIO_POWER_ENABLE, 1); - gpio.set_pin(drivers::GpioExpander::SD_CARD_POWER_ENABLE, 1); - gpio.set_pin(drivers::GpioExpander::SD_MUX_SWITCH, drivers::GpioExpander::SD_MUX_ESP); - }); + expander->with([&](auto& gpio) { + gpio.set_pin(drivers::GpioExpander::AUDIO_POWER_ENABLE, 1); + gpio.set_pin(drivers::GpioExpander::SD_CARD_POWER_ENABLE, 1); + gpio.set_pin(drivers::GpioExpander::SD_MUX_SWITCH, + drivers::GpioExpander::SD_MUX_ESP); + }); ESP_LOGI(TAG, "Init SD card"); auto storage_res = drivers::SdStorage::create(expander); @@ -119,6 +119,8 @@ extern "C" void app_main(void) { (void*)lvglArgs, 1, sLvglStack, &sLvglTaskBuffer, 1); + // TODO(jacqueline): re-enable this once our pipeline works. + /* ESP_LOGI(TAG, "Init audio pipeline"); auto playback_res = audio::AudioPlayback::create(expander, storage); if (playback_res.has_error()) { @@ -127,9 +129,10 @@ extern "C" void app_main(void) { } std::shared_ptr playback = std::move(playback_res.value()); + */ ESP_LOGI(TAG, "Launch console"); - console::AppConsole console(playback.get()); + console::AppConsole console(nullptr); console.Launch(); while (1) {