summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-06-19 08:51:34 +1000
committerjacqueline <me@jacqueline.id.au>2023-06-19 08:51:34 +1000
commit6ff8b5886ef91ed46dba08686900d519f6c9c62d (patch)
tree133daa91898e047fd93a5e83ba6990af2904e5a1
parent4e5dba158367f9b8b440e6c5051c95d9c22b76d7 (diff)
downloadtangara-fw-6ff8b5886ef91ed46dba08686900d519f6c9c62d.tar.gz
Support playing tracks by track id
-rw-r--r--src/audio/audio_decoder.cpp6
-rw-r--r--src/audio/audio_fsm.cpp46
-rw-r--r--src/audio/fatfs_audio_input.cpp30
-rw-r--r--src/audio/include/audio_events.hpp2
-rw-r--r--src/audio/include/audio_fsm.hpp11
-rw-r--r--src/audio/include/fatfs_audio_input.hpp3
-rw-r--r--src/database/database.cpp12
-rw-r--r--src/database/include/database.hpp2
-rw-r--r--src/system_fsm/include/system_events.hpp7
-rw-r--r--src/system_fsm/running.cpp2
-rw-r--r--src/tasks/tasks.cpp2
11 files changed, 112 insertions, 11 deletions
diff --git a/src/audio/audio_decoder.cpp b/src/audio/audio_decoder.cpp
index abb94e85..b4af65fb 100644
--- a/src/audio/audio_decoder.cpp
+++ b/src/audio/audio_decoder.cpp
@@ -89,9 +89,11 @@ auto AudioDecoder::Process(const std::vector<InputStream>& inputs,
// Check the input stream's format has changed (or, by extension, if this is
// the first stream).
if (!current_input_format_ || *current_input_format_ != info.format) {
- ESP_LOGI(kTag, "beginning new stream");
has_samples_to_send_ = false;
- ProcessStreamInfo(info);
+ if (!ProcessStreamInfo(info)) {
+ return;
+ }
+ ESP_LOGI(kTag, "beginning new stream");
auto res = current_codec_->BeginStream(input->data());
input->consume(res.first);
if (res.second.has_error()) {
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp
index 0be28250..a65b9f3b 100644
--- a/src/audio/audio_fsm.cpp
+++ b/src/audio/audio_fsm.cpp
@@ -5,6 +5,7 @@
*/
#include "audio_fsm.hpp"
+#include <future>
#include <memory>
#include <variant>
#include "audio_decoder.hpp"
@@ -14,6 +15,7 @@
#include "i2s_audio_output.hpp"
#include "i2s_dac.hpp"
#include "pipeline.hpp"
+#include "track.hpp"
namespace audio {
@@ -59,18 +61,38 @@ auto AudioState::Init(drivers::GpioExpander* gpio_expander,
return true;
}
+void AudioState::react(const system_fsm::StorageMounted& ev) {
+ sDatabase = ev.db;
+}
+
namespace states {
void Uninitialised::react(const system_fsm::BootComplete&) {
transit<Standby>();
}
-void Standby::react(const PlayFile& ev) {
- if (sFileSource->OpenFile(ev.filename)) {
- transit<Playback>();
+void Standby::react(const InputFileOpened& ev) {
+ transit<Playback>();
+}
+
+void Standby::react(const PlayTrack& ev) {
+ auto db = sDatabase.lock();
+ if (!db) {
+ ESP_LOGW(kTag, "database not open; ignoring play request");
+ return;
+ }
+
+ if (ev.data) {
+ sFileSource->OpenFile(ev.data->filepath());
+ } else {
+ sFileSource->OpenFile(db->GetTrackPath(ev.id));
}
}
+void Standby::react(const PlayFile& ev) {
+ sFileSource->OpenFile(ev.filename);
+}
+
void Playback::entry() {
ESP_LOGI(kTag, "beginning playback");
sI2SOutput->SetInUse(true);
@@ -81,6 +103,16 @@ void Playback::exit() {
sI2SOutput->SetInUse(false);
}
+void Playback::react(const PlayTrack& ev) {
+ sTrackQueue.push_back(EnqueuedItem(ev.id));
+}
+
+void Playback::react(const PlayFile& ev) {
+ sTrackQueue.push_back(EnqueuedItem(ev.filename));
+}
+
+void Playback::react(const InputFileOpened& ev) {}
+
void Playback::react(const InputFileFinished& ev) {
ESP_LOGI(kTag, "finished file");
if (sTrackQueue.empty()) {
@@ -91,6 +123,14 @@ void Playback::react(const InputFileFinished& ev) {
if (std::holds_alternative<std::string>(next_item)) {
sFileSource->OpenFile(std::get<std::string>(next_item));
+ } else if (std::holds_alternative<database::TrackId>(next_item)) {
+ auto db = sDatabase.lock();
+ if (!db) {
+ ESP_LOGW(kTag, "database not open; ignoring play request");
+ return;
+ }
+ sFileSource->OpenFile(
+ db->GetTrackPath(std::get<database::TrackId>(next_item)));
}
}
diff --git a/src/audio/fatfs_audio_input.cpp b/src/audio/fatfs_audio_input.cpp
index c26ff0ad..77b104d3 100644
--- a/src/audio/fatfs_audio_input.cpp
+++ b/src/audio/fatfs_audio_input.cpp
@@ -8,7 +8,9 @@
#include <stdint.h>
#include <algorithm>
+#include <chrono>
#include <cstdint>
+#include <future>
#include <memory>
#include <string>
#include <variant>
@@ -38,6 +40,7 @@ namespace audio {
FatfsAudioInput::FatfsAudioInput()
: IAudioElement(),
+ pending_path_(),
current_file_(),
is_file_open_(false),
current_container_(),
@@ -45,11 +48,19 @@ FatfsAudioInput::FatfsAudioInput()
FatfsAudioInput::~FatfsAudioInput() {}
+auto FatfsAudioInput::OpenFile(std::future<std::optional<std::string>>&& path)
+ -> void {
+ pending_path_ = std::move(path);
+}
+
auto FatfsAudioInput::OpenFile(const std::string& path) -> bool {
if (is_file_open_) {
f_close(&current_file_);
is_file_open_ = false;
}
+ if (pending_path_) {
+ pending_path_ = {};
+ }
ESP_LOGI(kTag, "opening file %s", path.c_str());
database::TagParserImpl tag_parser;
@@ -89,16 +100,33 @@ auto FatfsAudioInput::OpenFile(const std::string& path) -> bool {
return false;
}
+ events::Dispatch<InputFileOpened, AudioState>({});
is_file_open_ = true;
return true;
}
auto FatfsAudioInput::NeedsToProcess() const -> bool {
- return is_file_open_;
+ return is_file_open_ || pending_path_;
}
auto FatfsAudioInput::Process(const std::vector<InputStream>& inputs,
OutputStream* output) -> void {
+ if (pending_path_) {
+ ESP_LOGI(kTag, "waiting for path");
+ if (!pending_path_->valid()) {
+ pending_path_ = {};
+ } else {
+ if (pending_path_->wait_for(std::chrono::seconds(0)) ==
+ std::future_status::ready) {
+ ESP_LOGI(kTag, "path ready!");
+ auto result = pending_path_->get();
+ if (result) {
+ OpenFile(*result);
+ }
+ }
+ }
+ }
+
if (!is_file_open_) {
return;
}
diff --git a/src/audio/include/audio_events.hpp b/src/audio/include/audio_events.hpp
index eebf5efe..60a0740c 100644
--- a/src/audio/include/audio_events.hpp
+++ b/src/audio/include/audio_events.hpp
@@ -21,9 +21,9 @@ struct PlayFile : tinyfsm::Event {
struct PlayTrack : tinyfsm::Event {
database::TrackId id;
std::optional<database::TrackData> data;
- std::optional<database::TrackTags> tags;
};
+struct InputFileOpened : tinyfsm::Event {};
struct InputFileFinished : tinyfsm::Event {};
struct AudioPipelineIdle : tinyfsm::Event {};
diff --git a/src/audio/include/audio_fsm.hpp b/src/audio/include/audio_fsm.hpp
index 72654ab5..bd902706 100644
--- a/src/audio/include/audio_fsm.hpp
+++ b/src/audio/include/audio_fsm.hpp
@@ -38,10 +38,13 @@ class AudioState : public tinyfsm::Fsm<AudioState> {
/* Fallback event handler. Does nothing. */
void react(const tinyfsm::Event& ev) {}
+ void react(const system_fsm::StorageMounted&);
+
virtual void react(const system_fsm::BootComplete&) {}
virtual void react(const PlayTrack&) {}
virtual void react(const PlayFile&) {}
+ virtual void react(const InputFileOpened&) {}
virtual void react(const InputFileFinished&) {}
virtual void react(const AudioPipelineIdle&) {}
@@ -69,8 +72,10 @@ class Uninitialised : public AudioState {
class Standby : public AudioState {
public:
- void react(const PlayTrack&) override {}
+ void react(const InputFileOpened&) override;
+ void react(const PlayTrack&) override;
void react(const PlayFile&) override;
+
using AudioState::react;
};
@@ -79,6 +84,10 @@ class Playback : public AudioState {
void entry() override;
void exit() override;
+ void react(const PlayTrack&) override;
+ void react(const PlayFile&) override;
+
+ void react(const InputFileOpened&) override;
void react(const InputFileFinished&) override;
void react(const AudioPipelineIdle&) override;
diff --git a/src/audio/include/fatfs_audio_input.hpp b/src/audio/include/fatfs_audio_input.hpp
index f5a65d0d..ab392f54 100644
--- a/src/audio/include/fatfs_audio_input.hpp
+++ b/src/audio/include/fatfs_audio_input.hpp
@@ -7,6 +7,7 @@
#pragma once
#include <cstdint>
+#include <future>
#include <memory>
#include <string>
#include <vector>
@@ -33,6 +34,7 @@ class FatfsAudioInput : public IAudioElement {
FatfsAudioInput();
~FatfsAudioInput();
+ auto OpenFile(std::future<std::optional<std::string>>&& path) -> void;
auto OpenFile(const std::string& path) -> bool;
auto NeedsToProcess() const -> bool override;
@@ -47,6 +49,7 @@ class FatfsAudioInput : public IAudioElement {
auto ContainerToStreamType(database::Encoding)
-> std::optional<codecs::StreamType>;
+ std::optional<std::future<std::optional<std::string>>> pending_path_;
FIL current_file_;
bool is_file_open_;
diff --git a/src/database/database.cpp b/src/database/database.cpp
index a96b3eab..ac5e4873 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -229,6 +229,18 @@ auto Database::Update() -> std::future<void> {
});
}
+auto Database::GetTrackPath(TrackId id)
+ -> std::future<std::optional<std::string>> {
+ return worker_task_->Dispatch<std::optional<std::string>>(
+ [=, this]() -> std::optional<std::string> {
+ auto track_data = dbGetTrackData(id);
+ if (track_data) {
+ return track_data->filepath();
+ }
+ return {};
+ });
+}
+
auto Database::GetTracks(std::size_t page_size) -> std::future<Result<Track>*> {
return worker_task_->Dispatch<Result<Track>*>([=, this]() -> Result<Track>* {
Continuation<Track> c{.iterator = nullptr,
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index 1a8388e8..8fecc5f6 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -82,6 +82,8 @@ class Database {
auto Update() -> std::future<void>;
+ auto GetTrackPath(TrackId id) -> std::future<std::optional<std::string>>;
+
auto GetTracks(std::size_t page_size) -> std::future<Result<Track>*>;
auto GetDump(std::size_t page_size) -> std::future<Result<std::string>*>;
diff --git a/src/system_fsm/include/system_events.hpp b/src/system_fsm/include/system_events.hpp
index 38929616..ec202c69 100644
--- a/src/system_fsm/include/system_events.hpp
+++ b/src/system_fsm/include/system_events.hpp
@@ -6,6 +6,9 @@
#pragma once
+#include <memory>
+
+#include "database.hpp"
#include "tinyfsm.hpp"
namespace system_fsm {
@@ -38,7 +41,9 @@ struct StorageUnmountRequested : tinyfsm::Event {};
/*
* Sent by SysState when the system storage has been successfully mounted.
*/
-struct StorageMounted : tinyfsm::Event {};
+struct StorageMounted : tinyfsm::Event {
+ std::weak_ptr<database::Database> db;
+};
struct StorageError : tinyfsm::Event {};
diff --git a/src/system_fsm/running.cpp b/src/system_fsm/running.cpp
index f9ff6140..87c25440 100644
--- a/src/system_fsm/running.cpp
+++ b/src/system_fsm/running.cpp
@@ -50,7 +50,7 @@ void Running::entry() {
ESP_LOGI(kTag, "storage loaded okay");
events::Dispatch<StorageMounted, SystemState, audio::AudioState, ui::UiState>(
- StorageMounted());
+ StorageMounted{.db = sDatabase});
}
void Running::exit() {
diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp
index c28f463c..7365813e 100644
--- a/src/tasks/tasks.cpp
+++ b/src/tasks/tasks.cpp
@@ -45,7 +45,7 @@ auto AllocateStack() -> cpp::span<StackType_t>;
// amount of stack space.
template <>
auto AllocateStack<Type::kAudio>() -> cpp::span<StackType_t> {
- std::size_t size = 32 * 1024;
+ std::size_t size = 48 * 1024;
return {static_cast<StackType_t*>(heap_caps_malloc(size, MALLOC_CAP_DEFAULT)),
size};
}