summaryrefslogtreecommitdiff
path: root/src/audio/audio_fsm.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-02-05 11:02:45 +1100
committerjacqueline <me@jacqueline.id.au>2024-02-05 11:03:52 +1100
commit299f3cc48f683d3e6dec1efb4957fdb49b4de2c3 (patch)
tree6eb0445c300492e53cdc048f12cc6780a12c55eb /src/audio/audio_fsm.cpp
parent811c335c2ac425320a1949ab23378172e86ae60a (diff)
downloadtangara-fw-299f3cc48f683d3e6dec1efb4957fdb49b4de2c3.tar.gz
Preserve the queue when going into standby
Diffstat (limited to 'src/audio/audio_fsm.cpp')
-rw-r--r--src/audio/audio_fsm.cpp73
1 files changed, 59 insertions, 14 deletions
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp
index 560e655a..e37c887b 100644
--- a/src/audio/audio_fsm.cpp
+++ b/src/audio/audio_fsm.cpp
@@ -49,6 +49,7 @@ std::shared_ptr<BluetoothAudioOutput> AudioState::sBtOutput;
std::shared_ptr<IAudioOutput> AudioState::sOutput;
std::optional<database::TrackId> AudioState::sCurrentTrack;
+bool AudioState::sIsPlaybackAllowed;
void AudioState::react(const system_fsm::KeyLockChanged& ev) {
if (ev.locking && sServices) {
@@ -138,6 +139,23 @@ auto AudioState::playTrack(database::TrackId id) -> void {
});
}
+auto AudioState::readyToPlay() -> bool {
+ return sCurrentTrack.has_value() && sIsPlaybackAllowed;
+}
+
+void AudioState::react(const TogglePlayPause& ev) {
+ sIsPlaybackAllowed = !sIsPlaybackAllowed;
+ if (readyToPlay()) {
+ if (!is_in_state<states::Playback>()) {
+ transit<states::Playback>();
+ }
+ } else {
+ if (!is_in_state<states::Standby>()) {
+ transit<states::Standby>();
+ }
+ }
+}
+
namespace states {
void Uninitialised::react(const system_fsm::BootComplete& ev) {
@@ -199,21 +217,55 @@ void Playback::react(const PlayFile& ev) {
}
void Standby::react(const internal::InputFileOpened& ev) {
- transit<Playback>();
+ if (readyToPlay()) {
+ transit<Playback>();
+ }
}
void Standby::react(const QueueUpdate& ev) {
auto current_track = sServices->track_queue().current();
- if (!current_track || (sCurrentTrack && *sCurrentTrack == *current_track)) {
+ if (!current_track || (sCurrentTrack && (*sCurrentTrack == *current_track))) {
return;
}
playTrack(*current_track);
}
-void Standby::react(const TogglePlayPause& ev) {
- if (sCurrentTrack) {
- transit<Playback>();
+static const char kQueueKey[] = "audio:queue";
+
+void Standby::react(const system_fsm::KeyLockChanged& ev) {
+ if (!ev.locking) {
+ return;
}
+ sServices->bg_worker().Dispatch<void>([]() {
+ auto db = sServices->database().lock();
+ if (!db) {
+ return;
+ }
+ auto& queue = sServices->track_queue();
+ if (queue.totalSize() <= queue.currentPosition()) {
+ // Nothing is playing, so don't bother saving the queue.
+ db->put(kQueueKey, "");
+ return;
+ }
+ db->put(kQueueKey, queue.serialise());
+ });
+}
+
+void Standby::react(const system_fsm::StorageMounted& ev) {
+ sServices->bg_worker().Dispatch<void>([]() {
+ auto db = sServices->database().lock();
+ if (!db) {
+ return;
+ }
+ auto res = db->get(kQueueKey);
+ if (res) {
+ // 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);
+ }
+ });
}
void Playback::entry() {
@@ -226,17 +278,14 @@ void Playback::entry() {
void Playback::exit() {
ESP_LOGI(kTag, "finishing playback");
- // TODO(jacqueline): Second case where it's useful to wait for the i2s buffer
- // to drain.
- vTaskDelay(pdMS_TO_TICKS(10));
sOutput->SetMode(IAudioOutput::Modes::kOnPaused);
// Stash the current volume now, in case it changed during playback, since we
// might be powering off soon.
sServices->nvs().AmpCurrentVolume(sOutput->GetVolume());
- events::System().Dispatch(PlaybackFinished{});
- events::Ui().Dispatch(PlaybackFinished{});
+ events::System().Dispatch(PlaybackStopped{});
+ events::Ui().Dispatch(PlaybackStopped{});
}
void Playback::react(const system_fsm::HasPhonesChanged& ev) {
@@ -259,10 +308,6 @@ void Playback::react(const QueueUpdate& ev) {
playTrack(*current_track);
}
-void Playback::react(const TogglePlayPause& ev) {
- transit<Standby>();
-}
-
void Playback::react(const PlaybackUpdate& ev) {
ESP_LOGI(kTag, "elapsed: %lu, total: %lu", ev.seconds_elapsed,
ev.track->duration);