diff options
Diffstat (limited to 'src/audio/audio_fsm.cpp')
| -rw-r--r-- | src/audio/audio_fsm.cpp | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index d4272c3d..05c7c216 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -13,6 +13,8 @@ #include "audio_sink.hpp" #include "bluetooth_types.hpp" +#include "cppbor.h" +#include "cppbor_parse.h" #include "esp_heap_caps.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" @@ -58,6 +60,8 @@ StreamBufferHandle_t AudioState::sDrainBuffer; std::optional<database::TrackId> AudioState::sCurrentTrack; bool AudioState::sIsPlaybackAllowed; +static std::optional<std::pair<std::string, uint32_t>> sLastTrackUpdate; + void AudioState::react(const system_fsm::BluetoothEvent& ev) { if (ev.event != drivers::bluetooth::Event::kConnectionStateChanged) { return; @@ -310,11 +314,15 @@ void Standby::react(const QueueUpdate& ev) { if (!current_track || (sCurrentTrack && (*sCurrentTrack == *current_track))) { return; } + if (ev.reason == QueueUpdate::Reason::kDeserialised && sLastTrackUpdate) { + return; + } clearDrainBuffer(); playTrack(*current_track); } static const char kQueueKey[] = "audio:queue"; +static const char kCurrentFileKey[] = "audio:current"; void Standby::react(const system_fsm::KeyLockChanged& ev) { if (!ev.locking) { @@ -332,6 +340,14 @@ void Standby::react(const system_fsm::KeyLockChanged& ev) { return; } db->put(kQueueKey, queue.serialise()); + + if (sLastTrackUpdate) { + cppbor::Array current_track{ + cppbor::Tstr{sLastTrackUpdate->first}, + cppbor::Uint{sLastTrackUpdate->second}, + }; + db->put(kCurrentFileKey, current_track.toString()); + } }); } @@ -341,13 +357,32 @@ void Standby::react(const system_fsm::StorageMounted& ev) { if (!db) { return; } - auto res = db->get(kQueueKey); - if (res) { + + // Restore the currently playing file before restoring the queue. This way, + // we can fall back to restarting the queue's current track if there's any + // issue restoring the current file. + auto current = db->get(kCurrentFileKey); + if (current) { + // Again, ensure we don't boot-loop by trying to play a track that causes + // a crash over and over again. + db->put(kCurrentFileKey, ""); + auto [parsed, unused, err] = cppbor::parse( + reinterpret_cast<uint8_t*>(current->data()), current->size()); + if (parsed->type() == cppbor::ARRAY) { + std::string filename = parsed->asArray()->get(0)->asTstr()->value(); + uint32_t pos = parsed->asArray()->get(1)->asUint()->value(); + sLastTrackUpdate = std::make_pair(filename, pos); + sFileSource->SetPath(filename, pos); + } + } + + auto queue = db->get(kQueueKey); + if (queue) { // Don't restore the same queue again. This ideally should do nothing, // but guards against bad edge cases where restoring the queue ends up // causing a crash. db->put(kQueueKey, ""); - sServices->track_queue().deserialise(*res); + sServices->track_queue().deserialise(*queue); } }); } @@ -399,6 +434,7 @@ void Playback::react(const QueueUpdate& ev) { void Playback::react(const PlaybackUpdate& ev) { ESP_LOGI(kTag, "elapsed: %lu, total: %lu", ev.seconds_elapsed, ev.track->duration); + sLastTrackUpdate = std::make_pair(ev.track->filepath, ev.seconds_elapsed); } void Playback::react(const internal::InputFileOpened& ev) {} @@ -407,6 +443,7 @@ void Playback::react(const internal::InputFileClosed& ev) {} void Playback::react(const internal::InputFileFinished& ev) { ESP_LOGI(kTag, "finished playing file"); + sLastTrackUpdate.reset(); sServices->track_queue().finish(); if (!sServices->track_queue().current()) { for (int i = 0; i < 20; i++) { |
