include repeat, replay, and shuffle in persisted queue info

custom
jacqueline 1 year ago
parent cb379f4bc3
commit 786546653a
  1. 39
      src/audio/include/track_queue.hpp
  2. 150
      src/audio/track_queue.cpp

@ -12,6 +12,7 @@
#include <shared_mutex> #include <shared_mutex>
#include <vector> #include <vector>
#include "cppbor_parse.h"
#include "database.hpp" #include "database.hpp"
#include "tasks.hpp" #include "tasks.hpp"
#include "track.hpp" #include "track.hpp"
@ -24,6 +25,7 @@ namespace audio {
*/ */
class RandomIterator { class RandomIterator {
public: public:
RandomIterator();
RandomIterator(size_t size); RandomIterator(size_t size);
auto current() const -> size_t; auto current() const -> size_t;
@ -35,6 +37,10 @@ class RandomIterator {
auto resize(size_t) -> void; auto resize(size_t) -> void;
auto replay(bool) -> void; auto replay(bool) -> void;
auto seed() -> size_t& { return seed_; }
auto pos() -> size_t& { return pos_; }
auto size() -> size_t& { return size_; }
private: private:
size_t seed_; size_t seed_;
size_t pos_; size_t pos_;
@ -90,7 +96,6 @@ class TrackQueue {
*/ */
auto finish() -> void; auto finish() -> void;
auto skipTo(database::TrackId) -> void; auto skipTo(database::TrackId) -> void;
/* /*
@ -125,6 +130,38 @@ class TrackQueue {
std::optional<RandomIterator> shuffle_; std::optional<RandomIterator> shuffle_;
bool repeat_; bool repeat_;
bool replay_; bool replay_;
class QueueParseClient : public cppbor::ParseClient {
public:
QueueParseClient(TrackQueue& queue);
ParseClient* item(std::unique_ptr<cppbor::Item>& item,
const uint8_t* hdrBegin,
const uint8_t* valueBegin,
const uint8_t* end) override;
ParseClient* itemEnd(std::unique_ptr<cppbor::Item>& item,
const uint8_t* hdrBegin,
const uint8_t* valueBegin,
const uint8_t* end) override;
void error(const uint8_t* position,
const std::string& errorMessage) override {}
private:
TrackQueue& queue_;
enum class State {
kInit,
kRoot,
kMetadata,
kShuffle,
kTracks,
kFinished,
};
State state_;
size_t i_;
};
}; };
} // namespace audio } // namespace audio

@ -33,6 +33,9 @@ namespace audio {
[[maybe_unused]] static constexpr char kTag[] = "tracks"; [[maybe_unused]] static constexpr char kTag[] = "tracks";
RandomIterator::RandomIterator()
: seed_(0), pos_(0), size_(0), replay_(false) {}
RandomIterator::RandomIterator(size_t size) RandomIterator::RandomIterator(size_t size)
: seed_(), pos_(0), size_(size), replay_(false) { : seed_(), pos_(0), size_(size), replay_(false) {
esp_fill_random(&seed_, sizeof(seed_)); esp_fill_random(&seed_, sizeof(seed_));
@ -338,66 +341,127 @@ auto TrackQueue::serialise() -> std::string {
for (database::TrackId track : tracks_) { for (database::TrackId track : tracks_) {
tracks.add(cppbor::Uint(track)); tracks.add(cppbor::Uint(track));
} }
// FIXME: this should include the RandomIterator's seed as well. cppbor::Map encoded;
cppbor::Array encoded{ encoded.add(cppbor::Uint{0}, cppbor::Array{
cppbor::Uint{pos_}, cppbor::Uint{pos_},
std::move(tracks), cppbor::Bool{repeat_},
}; cppbor::Bool{replay_},
});
if (shuffle_) {
encoded.add(cppbor::Uint{1}, cppbor::Array{
cppbor::Uint{shuffle_->size()},
cppbor::Uint{shuffle_->seed()},
cppbor::Uint{shuffle_->pos()},
});
}
encoded.add(cppbor::Uint{2}, std::move(tracks));
return encoded.toString(); return encoded.toString();
} }
class QueueParseClient : public cppbor::ParseClient { TrackQueue::QueueParseClient::QueueParseClient(TrackQueue& queue)
public: : queue_(queue), state_(State::kInit), i_(0) {}
QueueParseClient(size_t& pos, std::pmr::vector<database::TrackId>& tracks)
: pos_(pos), cppbor::ParseClient* TrackQueue::QueueParseClient::item(
tracks_(tracks), std::unique_ptr<cppbor::Item>& item,
in_root_array_(false), const uint8_t* hdrBegin,
in_track_list_(false) {} const uint8_t* valueBegin,
const uint8_t* end) {
ParseClient* item(std::unique_ptr<cppbor::Item>& item, if (state_ == State::kInit) {
const uint8_t* hdrBegin, if (item->type() == cppbor::MAP) {
const uint8_t* valueBegin, state_ = State::kRoot;
const uint8_t* end) override { }
} else if (state_ == State::kRoot) {
if (item->type() == cppbor::UINT) {
switch (item->asUint()->unsignedValue()) {
case 0:
state_ = State::kMetadata;
break;
case 1:
state_ = State::kShuffle;
break;
case 2:
state_ = State::kTracks;
break;
default:
state_ = State::kFinished;
}
}
} else if (state_ == State::kMetadata) {
if (item->type() == cppbor::ARRAY) { if (item->type() == cppbor::ARRAY) {
if (!in_root_array_) { i_ = 0;
in_root_array_ = true; } else if (item->type() == cppbor::UINT) {
} else { queue_.pos_ = item->asUint()->unsignedValue();
in_track_list_ = true; } else if (item->type() == cppbor::SIMPLE) {
bool val = item->asBool()->value();
if (i_ == 0) {
queue_.repeat_ = val;
} else if (i_ == 1) {
queue_.replay_ = val;
} }
i_++;
}
} else if (state_ == State::kShuffle) {
if (item->type() == cppbor::ARRAY) {
i_ = 0;
queue_.shuffle_.emplace();
queue_.shuffle_->replay(queue_.replay_);
} else if (item->type() == cppbor::UINT) { } else if (item->type() == cppbor::UINT) {
auto val = item->asUint()->unsignedValue(); auto val = item->asUint()->unsignedValue();
if (in_track_list_) { switch (i_) {
tracks_.push_back(val); case 0:
} else { queue_.shuffle_->size() = val;
pos_ = static_cast<size_t>(val); break;
case 1:
queue_.shuffle_->seed() = val;
break;
case 2:
queue_.shuffle_->pos() = val;
break;
default:
break;
} }
i_++;
} }
return this; } else if (state_ == State::kTracks) {
if (item->type() == cppbor::UINT) {
queue_.tracks_.push_back(item->asUint()->unsignedValue());
}
} else if (state_ == State::kFinished) {
} }
return this;
}
ParseClient* itemEnd(std::unique_ptr<cppbor::Item>& item, cppbor::ParseClient* TrackQueue::QueueParseClient::itemEnd(
const uint8_t* hdrBegin, std::unique_ptr<cppbor::Item>& item,
const uint8_t* valueBegin, const uint8_t* hdrBegin,
const uint8_t* end) override { const uint8_t* valueBegin,
return this; const uint8_t* end) {
if (state_ == State::kInit) {
state_ = State::kFinished;
} else if (state_ == State::kRoot) {
state_ = State::kFinished;
} else if (state_ == State::kMetadata) {
if (item->type() == cppbor::ARRAY) {
state_ = State::kRoot;
}
} else if (state_ == State::kShuffle) {
if (item->type() == cppbor::ARRAY) {
state_ = State::kRoot;
}
} else if (state_ == State::kTracks) {
if (item->type() == cppbor::ARRAY) {
state_ = State::kRoot;
}
} else if (state_ == State::kFinished) {
} }
return this;
void error(const uint8_t* position, }
const std::string& errorMessage) override {}
private:
size_t& pos_;
std::pmr::vector<database::TrackId>& tracks_;
bool in_root_array_;
bool in_track_list_;
};
auto TrackQueue::deserialise(const std::string& s) -> void { auto TrackQueue::deserialise(const std::string& s) -> void {
if (s.empty()) { if (s.empty()) {
return; return;
} }
QueueParseClient client{pos_, tracks_}; QueueParseClient client{*this};
const uint8_t* data = reinterpret_cast<const uint8_t*>(s.data()); const uint8_t* data = reinterpret_cast<const uint8_t*>(s.data());
cppbor::parse(data, data + s.size(), &client); cppbor::parse(data, data + s.size(), &client);
notifyChanged(true); notifyChanged(true);

Loading…
Cancel
Save