Add additional cache file for playlist table of contents

custom
ailurux 7 months ago
parent 3490cceb6b
commit a169e60cac
  1. 123
      src/tangara/audio/playlist.cpp
  2. 3
      src/tangara/audio/playlist.hpp
  3. 3
      src/tangara/audio/track_queue.cpp

@ -42,10 +42,12 @@ auto Playlist::open() -> bool {
file_open_ = true; file_open_ = true;
file_error_ = false; file_error_ = false;
if (!deserialiseCache()) {
// Count the playlist size and build our offset cache. // Count the playlist size and build our offset cache.
countItems(); countItems();
// Advance to the first item. // Advance to the first item.
skipToWithoutCache(0); skipToWithoutCache(0);
}
return !file_error_; return !file_error_;
} }
@ -100,6 +102,127 @@ auto Playlist::skipTo(size_t position) -> void {
skipToLocked(position); skipToLocked(position);
} }
// Serialise the cache to a file to avoid having to rescan
// the entire queue when resuming
auto Playlist::serialiseCache() -> bool {
std::unique_lock<std::mutex> lock(mutex_);
if (!file_open_) {
return false;
}
FIL file;
// Open the cache file
std::string cache_file = filepath_ + ".cache";
FRESULT res =
f_open(&file, cache_file.c_str(), FA_READ | FA_WRITE | FA_CREATE_ALWAYS);
if (res != FR_OK) {
ESP_LOGE(kTag, "failed to open cache file! res: %i", res);
return false;
}
uint8_t header[8];
// First 4 bytes = file size of queue file (for checking this file matches)
uint32_t q_file_size = f_size(&file_);
header[0] = q_file_size >> 24;
header[1] = q_file_size >> 16;
header[2] = q_file_size >> 8;
header[3] = q_file_size;
// Next 4 bytes = number of tracks in this queue
header[4] = total_size_ >> 24;
header[5] = total_size_ >> 16;
header[6] = total_size_ >> 8;
header[7] = total_size_;
UINT bytes_written = 0;
f_write(&file, header, 8, &bytes_written);
if (bytes_written < 8) {
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);
return true;
}
auto Playlist::deserialiseCache() -> bool {
if (!file_open_) {
return false;
}
FIL file;
// Open the cache file
std::string cache_file = filepath_ + ".cache";
FRESULT res =
f_open(&file, cache_file.c_str(), FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
if (res != FR_OK) {
ESP_LOGE(kTag, "failed to open cache file! res: %i", res);
return false;
}
uint8_t header[8];
UINT bytes_read;
f_read(&file, header, 8, &bytes_read);
uint32_t file_size_check = header[0] << 24 |
header[1] << 16 |
header[2] << 8 |
header[3];
// TODO: Handle this conversion safely
if (file_size_check != (uint32_t)f_size(&file_)) {
ESP_LOGE("DANIEL", "Check didn't match. File size check: %lu, actual size: %llu", file_size_check, f_size(&file_));
return false;
}
uint32_t size = header[4] << 24 |
header[5] << 16 |
header[6] << 8 |
header[7];
total_size_ = size;
// Read in the cache
uint8_t buf[8];
size_t idx = 0;
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);
return true;
}
auto Playlist::skipToLocked(size_t position) -> void { auto Playlist::skipToLocked(size_t position) -> void {
if (!file_open_ || file_error_) { if (!file_open_ || file_error_) {
return; return;

@ -45,6 +45,9 @@ class Playlist {
auto prev() -> void; auto prev() -> void;
auto skipTo(size_t position) -> void; auto skipTo(size_t position) -> void;
auto serialiseCache() -> bool;
auto deserialiseCache() -> bool;
protected: protected:
const std::string filepath_; const std::string filepath_;

@ -422,6 +422,9 @@ auto TrackQueue::serialise() -> std::string {
cppbor::Uint{shuffle_->pos()}, cppbor::Uint{shuffle_->pos()},
}); });
} }
playlist_.serialiseCache();
return encoded.toString(); return encoded.toString();
} }

Loading…
Cancel
Save