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. 134
      src/audio/track_queue.cpp

@ -12,6 +12,7 @@
#include <shared_mutex>
#include <vector>
#include "cppbor_parse.h"
#include "database.hpp"
#include "tasks.hpp"
#include "track.hpp"
@ -24,6 +25,7 @@ namespace audio {
*/
class RandomIterator {
public:
RandomIterator();
RandomIterator(size_t size);
auto current() const -> size_t;
@ -35,6 +37,10 @@ class RandomIterator {
auto resize(size_t) -> void;
auto replay(bool) -> void;
auto seed() -> size_t& { return seed_; }
auto pos() -> size_t& { return pos_; }
auto size() -> size_t& { return size_; }
private:
size_t seed_;
size_t pos_;
@ -90,7 +96,6 @@ class TrackQueue {
*/
auto finish() -> void;
auto skipTo(database::TrackId) -> void;
/*
@ -125,6 +130,38 @@ class TrackQueue {
std::optional<RandomIterator> shuffle_;
bool repeat_;
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

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

Loading…
Cancel
Save