Use cppbor for encoding playlist toc

Also fix a locking issue with opening+clearing

Co-authored-by: ailurux <ailuruxx@gmail.com>
custom
jacqueline 7 months ago
parent ea71fa5d2b
commit 6318b27284
  1. 93
      src/tangara/audio/playlist.cpp
  2. 7
      src/tangara/audio/playlist.hpp

@ -4,9 +4,12 @@
* SPDX-License-Identifier: GPL-3.0-only * SPDX-License-Identifier: GPL-3.0-only
*/ */
#include "playlist.hpp" #include "playlist.hpp"
#include <stdint.h>
#include <string> #include <string>
#include "cppbor.h"
#include "cppbor_parse.h"
#include "esp_log.h" #include "esp_log.h"
#include "ff.h" #include "ff.h"
@ -121,48 +124,25 @@ auto Playlist::serialiseCache() -> bool {
return false; return false;
} }
uint8_t header[12]; cppbor::Array data;
// First item = file size of queue file (for checking this file matches)
data.add(f_size(&file_));
// Next item = number of tracks in this queue
data.add(total_size_);
// First 8 bytes = file size of queue file (for checking this file matches) // Next, write out every cached offset
uint64_t q_file_size = f_size(&file_); for (uint64_t offset : offset_cache_) {
header[0] = q_file_size >> 56; data.add(offset);
header[1] = q_file_size >> 48; }
header[2] = q_file_size >> 40;
header[3] = q_file_size >> 32;
header[4] = q_file_size >> 24;
header[5] = q_file_size >> 16;
header[6] = q_file_size >> 8;
header[7] = q_file_size;
// Next 4 bytes = number of tracks in this queue auto encoded = data.encode();
header[8] = total_size_ >> 24;
header[9] = total_size_ >> 16;
header[10] = total_size_ >> 8;
header[11] = total_size_;
UINT bytes_written = 0; UINT bytes_written = 0;
f_write(&file, header, 12, &bytes_written); f_write(&file, encoded.data(), encoded.size(), &bytes_written);
if (bytes_written < 12) { if (bytes_written != encoded.size()) {
return false; return false;
} }
// Next, write out every cached offset
for (uint64_t offset : offset_cache_) {
uint8_t bytes_out[8];
bytes_out[0] = offset >> 56;
bytes_out[1] = offset >> 48;
bytes_out[2] = offset >> 40;
bytes_out[3] = offset >> 32;
bytes_out[4] = offset >> 24;
bytes_out[5] = offset >> 16;
bytes_out[6] = offset >> 8;
bytes_out[7] = offset;
f_write(&file, bytes_out, 8, &bytes_written);
if (bytes_written < 8) {
return false;
}
}
f_close(&file); f_close(&file);
return true; return true;
} }
@ -183,36 +163,31 @@ auto Playlist::deserialiseCache() -> bool {
return false; return false;
} }
uint8_t header[8]; std::vector<uint8_t> encoded;
encoded.resize(f_size(&file));
UINT bytes_read; UINT bytes_read;
f_read(&file, header, 12, &bytes_read); f_read(&file, encoded.data(), encoded.size(), &bytes_read);
if (bytes_read != 12) { if (bytes_read != encoded.size()) {
return false;
}
auto [data, unused, err] = cppbor::parse(encoded);
if (!data || data->type() != cppbor::ARRAY) {
return false; return false;
} }
uint64_t file_size_check = auto entries = data->asArray();
header[0] << 56 | header[1] << 48 | header[2] << 40 | header[3] << 32 |
header[4] << 24 | header[5] << 16 | header[6] << 8 | header[7];
if (file_size_check != f_size(&file_)) { // Double check the expected file size matches.
if (entries->get(0)->asUint()->unsignedValue() != f_size(&file_)) {
return false; return false;
} }
uint32_t size = total_size_ = entries->get(1)->asUint()->unsignedValue();
header[8] << 24 | header[9] << 16 | header[10] << 8 | header[11];
total_size_ = size;
// Read in the cache // Read in the cache
uint8_t buf[8]; for (size_t i = 2; i < entries->size(); i++) {
size_t idx = 0; offset_cache_.push_back(entries->get(i)->asUint()->unsignedValue());
while (true) {
f_read(&file, buf, 8, &bytes_read);
if (bytes_read == 0) {
break;
}
uint64_t offset = buf[0] << 56 | buf[1] << 48 | buf[2] << 40 |
buf[3] << 32 | buf[4] << 24 | buf[5] << 16 | buf[6] << 8 |
buf[7];
offset_cache_.push_back(offset);
} }
f_close(&file); f_close(&file);
@ -350,7 +325,7 @@ auto MutablePlaylist::open() -> bool {
// If there's no cache (or deserialising failed) and the queue is // If there's no cache (or deserialising failed) and the queue is
// sufficiently large, abort and clear the queue // sufficiently large, abort and clear the queue
if (queue_filesize > 50000) { if (queue_filesize > 50000) {
clear(); clearLocked();
} else { } else {
// Otherwise, read in the existing entries // Otherwise, read in the existing entries
countItems(); countItems();
@ -360,12 +335,14 @@ auto MutablePlaylist::open() -> bool {
} }
return !file_error_; return !file_error_;
return false;
} }
auto MutablePlaylist::clear() -> bool { auto MutablePlaylist::clear() -> bool {
std::unique_lock<std::mutex> lock(mutex_); std::unique_lock<std::mutex> lock(mutex_);
return clearLocked();
}
auto MutablePlaylist::clearLocked() -> bool {
// Try to recover from any IO errors. // Try to recover from any IO errors.
if (file_error_ && file_open_) { if (file_error_ && file_open_) {
file_error_ = false; file_error_ = false;

@ -33,7 +33,7 @@ class Playlist {
virtual ~Playlist(); virtual ~Playlist();
using Item = using Item =
std::variant<database::TrackId, database::TrackIterator, std::string>; std::variant<database::TrackId, database::TrackIterator, std::string>;
auto open() -> bool; virtual auto open() -> bool;
auto filepath() const -> std::string; auto filepath() const -> std::string;
auto currentPosition() const -> size_t; auto currentPosition() const -> size_t;
@ -82,10 +82,13 @@ class Playlist {
class MutablePlaylist : public Playlist { class MutablePlaylist : public Playlist {
public: public:
MutablePlaylist(const std::string& playlistFilepath); MutablePlaylist(const std::string& playlistFilepath);
auto open() -> bool; auto open() -> bool override;
auto clear() -> bool; auto clear() -> bool;
auto append(Item i) -> void; auto append(Item i) -> void;
private:
auto clearLocked() -> bool;
}; };
} // namespace audio } // namespace audio

Loading…
Cancel
Save