Keep music entry snapshots stable during paused restore

This commit is contained in:
liu weikai committed 2026-10-16 12:11:25 +08:00
1 parent 7898bfef56
commit 2d2a9e8973
3 files changed
+23 -2

No files matched your search

+3
View File
@@ -120,6 +120,9 @@ observable PSRAM/SD/audio ports. It verifies lazy task creation, idle volume,
hidden-pause cleanup and a UI card-change snapshot interleaved with worker
restore. That regression fails before the saved-record ownership transfer and
passes afterward; storage work remains outside the publication mutex.
Restore publishes the paused session before handing the record to the worker,
so a simultaneous entry snapshot keeps Now Playing routing. Published snapshots
are also scoped to their SD media session. The same test checks both conditions.
Preview screenshots use explicit deterministic fixtures; they are not evidence
of physical audio quality, bus timing, PSRAM peaks or real-device latency.
@@ -84,6 +84,7 @@ class Service final : public ::music::IService
TaskHandle_t worker_ = nullptr;
Runtime* runtime_ = nullptr;
::music::Snapshot* published_ = nullptr;
uint32_t published_session_ = 0;
::music::ResumeState* resume_ = nullptr;
::music::Artwork* artwork_ = nullptr;
::music::Request* requests_ = nullptr;
@@ -135,7 +136,11 @@ class Service final : public ::music::IService
{
Lock lock(*this);
if (!published_) published_ = ::music::make<::music::Snapshot>();
if (published_) *published_ = runtime.player.state;
if (published_)
{
*published_ = runtime.player.state;
published_session_ = sd::sd_media_session();
}
else failure_ = Failure::Memory;
auto* art = runtime.player.artwork();
if (art != artwork_)
@@ -192,6 +197,18 @@ class Service final : public ::music::IService
// UI snapshot may invalidate its own saved session after a card change.
if (resume_ && runtime->player.state.current.id == 0)
{
// Publish the existing session before transferring it, so an
// entry snapshot cannot briefly route a paused user to Library.
if (!published_) published_ = ::music::make<::music::Snapshot>();
if (published_)
{
published_->current = resume_->current;
published_->position_ms = resume_->position_ms;
published_->mode = resume_->mode;
published_->playback = ::music::Playback::Paused;
published_session_ = resume_->media_session;
}
else failure_ = Failure::Memory;
saved = resume_;
resume_ = nullptr;
}
@@ -352,7 +369,7 @@ class Service final : public ::music::IService
Lock lock(*this, pdMS_TO_TICKS(20));
if (!lock) return false;
if (resume_ && resume_->media_session != sd::sd_media_session()) ::music::destroy(resume_);
if (published_) out = *published_;
if (published_ && published_session_ == sd::sd_media_session()) out = *published_;
else
{
using Snapshot = ::music::Snapshot;
+1
View File
@@ -134,6 +134,7 @@ int main(int argc, char** argv)
{
if (runtime_test::ready_calls != 2) return; // First call belongs to Player construction.
runtime_test::on_ready = nullptr;
assert(snapshot().playback == music::Playback::Paused);
++runtime_test::session;
const auto out = snapshot();
assert(out.playback == music::Playback::Stopped);