2#include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
3#include "AudioTools/CoreAudio/AudioBasic/Str.h"
4#include "AudioTools/CoreAudio/AudioMetaData/AbstractMetaData.h"
30 LOGE(
"Not Supported!");
38 virtual int index() {
return -1; }
46 timeout_auto_next_value = millisec;
53 virtual bool setMetadataCallback(
void (*fn)(
MetaDataType info,
54 const char* str,
int len),
69 virtual const char*
toStr() {
return nullptr; }
72 int timeout_auto_next_value = 500;
86 void (*onStartCallback)() =
nullptr) {
88 this->onStartCallback = onStartCallback;
89 this->nextStreamCallback = nextStreamCallback;
95 if (onStartCallback !=
nullptr) onStartCallback();
102 return nextStreamCallback ==
nullptr ? nullptr : nextStreamCallback(offset);
107 LOGI(
"selectStream: %d",
index);
108 if (indexStreamCallback ==
nullptr) {
109 LOGI(
"setCallbackSelectStream not provided");
118 return indexStreamCallback(
index);
123 return indexStreamCallback ==
nullptr ? nullptr : indexStreamCallback(-1);
126 void setCallbackOnStart(
void (*callback)()) { onStartCallback = callback; }
128 void setCallbackNextStream(Stream* (*callback)(
int offset)) {
129 nextStreamCallback = callback;
132 void setCallbackSelectStream(Stream* (*callback)(
int idx)) {
133 indexStreamCallback = callback;
138 virtual void setAutoNext(
bool a) { auto_next = a; }
141 virtual const char*
getPath() {
return path; }
144 void (*onStartCallback)() =
nullptr;
145 bool auto_next =
true;
146 Stream* (*nextStreamCallback)(
int offset) =
nullptr;
147 Stream* (*indexStreamCallback)(
int index) =
nullptr;
148 const char* path =
nullptr;
160 FileEntry(
int pathIdx,
const char* fileName) : path_index(pathIdx) {
170 virtual void addName(
const char* nameWithPath) = 0;
181 : dataSource(dataSource), prefix(prefix) {}
182 void setPrefix(
const char* prefix) { this->prefix = prefix; }
183 size_t write(uint8_t ch)
override {
184 if (ch ==
'\n' || ch ==
'\r') {
186 if (line_buffer.
length() > 0) {
188 if (prefix !=
nullptr) {
192 name.add(line_buffer.
c_str());
193 LOGD(
"adding '%s'", name.c_str());
194 dataSource.addName(name.c_str());
197 LOGD(
"adding '%s'", line_buffer.
c_str());
198 dataSource.addName(line_buffer.
c_str());
200 line_buffer.
clear(
false);
205 line_buffer.
add((
char)ch);
210 size_t write(
const uint8_t* buffer,
size_t size)
override {
211 for (
size_t i = 0; i < size; i++) {
219 if (line_buffer.
length() > 0) {
220 dataSource.addName(line_buffer.
c_str());
227 Str line_buffer{200};
228 const char* prefix =
nullptr;
249template <
typename FileType>
252 typedef FileType* (*FileToStreamCallback)(
const char* path,
259 : nameToStreamCallback(callback) {}
265 current_stream =
nullptr;
271 if (files.empty())
return nullptr;
273 current_index += offset;
275 if (current_index < 0) {
276 current_index = files.size() - 1;
277 }
else if (current_index >= (
int)files.size()) {
287 if (files.empty() || index < 0 || index >= (
int)files.size()) {
288 LOGE(
"Invalid index: %d (size: %d)",
index, files.size());
292 current_index =
index;
294 LOGI(
"selectStream: %d -> %s",
index, fullPath.
c_str());
296 if (nameToStreamCallback) {
298 return current_stream;
301 LOGE(
"No file to stream callback set!");
308 if (path ==
nullptr)
return nullptr;
315 LOGE(
"File not found: %s", path);
320 virtual int index()
override {
return current_index; }
324 if (path ==
nullptr)
return -1;
327 for (
int i = 0; i < (int)files.size(); i++) {
329 if (fullPath.
equals(path)) {
337 void addName(
const char* nameWithPath)
override {
339 if (nameWithPath ==
nullptr)
return;
340 LOGI(
"addName: '%s'", nameWithPath);
343 StrView nameWithPathStr(nameWithPath);
344 int lastSlashPos = nameWithPathStr.
lastIndexOf(
"/");
345 int len = nameWithPathStr.
length();
349 if (lastSlashPos < 0) {
352 nameStr.
set(nameWithPath);
355 pathStr.
substring(nameWithPath, 0, lastSlashPos);
356 nameStr.
substring(nameWithPath, lastSlashPos + 1, len);
364 files.push_back(entry);
371 if (nameWithPath ==
nullptr)
return false;
373 int idx =
indexOf(nameWithPath);
375 LOGI(
"deleteName: '%s' at index %d", nameWithPath, idx);
379 LOGW(
"deleteName: File not found: '%s'", nameWithPath);
386 if (idx >= files.size()) {
387 LOGW(
"deleteIndex: Invalid index: %d (size: %d)", (
int)idx, files.size());
391 LOGI(
"deleteIndex: Removing file at index %d", (
int)idx);
392 files.erase(files.begin() + idx);
395 if (current_index >= (
int)idx) {
397 if (current_index < 0 && !files.empty()) {
406 template <
typename T,
size_t N>
408 for (
size_t i = 0; i < N; i++) {
416 path_registry.clear();
418 current_stream =
nullptr;
422 int size() {
return files.size(); }
429 nameToStreamCallback = callback;
434 if (current_stream) {
435 return *current_stream;
437 static FileType empty;
442 virtual const char*
toStr()
override {
443 if (current_index >= 0 && current_index < (
int)files.size()) {
445 return current_path.
c_str();
456 int current_index = 0;
457 FileType* current_stream =
nullptr;
458 FileToStreamCallback nameToStreamCallback =
nullptr;
463 if (path ==
nullptr) path =
"";
466 for (
int i = 0; i < (int)path_registry.size(); i++) {
467 if (strcmp(path_registry[i].c_str(), path) == 0) {
475 path_registry.push_back(newPath);
476 return path_registry.size() - 1;
484 if (index < 0 || index >= (
int)files.size()) {
492 if (entry.path_index >= 0 && entry.path_index < (
int)path_registry.size()) {
493 result = path_registry[entry.path_index].c_str();
507 if (pathIndex >= 0 && pathIndex < (
int)path_registry.size()) {
508 return path_registry[pathIndex].c_str();
531template <
typename FileType>
534 typedef FileType* (*FileToStreamCallback)(
const char* path, FileType& file);
541 : file_array(nameArray), array_size(N), nameToStreamCallback(callback) {}
545 FileToStreamCallback callback)
546 : file_array(nameArray),
548 nameToStreamCallback(callback) {}
554 current_stream =
nullptr;
560 if (array_size == 0)
return nullptr;
562 current_index += offset;
564 if (current_index < 0) {
565 current_index = array_size - 1;
566 }
else if (current_index >= (
int)array_size) {
576 if (array_size == 0 || index < 0 || index >= (
int)array_size) {
577 LOGE(
"Invalid index: %d (size: %d)",
index, array_size);
581 current_index =
index;
582 const char* filePath = file_array[
index];
583 LOGI(
"selectStream: %d -> %s",
index, filePath);
585 if (nameToStreamCallback && filePath) {
586 current_stream = nameToStreamCallback(filePath, getCurrentFile());
587 return current_stream;
590 LOGE(
"No file to stream callback set or invalid file path!");
597 if (path ==
nullptr)
return nullptr;
604 LOGE(
"File not found: %s", path);
609 virtual int index()
override {
return current_index; }
613 if (path ==
nullptr)
return -1;
616 for (
int i = 0; i < (int)array_size; i++) {
617 const char* filePath = file_array[i];
628 file_array = nameArray;
635 file_array = nameArray;
641 int size()
const {
return array_size; }
644 bool isEmpty()
const {
return array_size == 0; }
648 nameToStreamCallback = callback;
651 FileType& getCurrentFile() {
652 if (current_stream) {
653 return *current_stream;
655 static FileType empty;
661 if (
index >= 0 &&
index < (
int)array_size && file_array) {
662 return file_array[
index];
668 virtual const char*
toStr()
override {
669 if (current_index >= 0 && current_index < (
int)array_size && file_array) {
670 return file_array[current_index];
679 const char*
const* file_array =
nullptr;
680 size_t array_size = 0;
681 int current_index = 0;
682 FileType* current_stream =
nullptr;
683 FileToStreamCallback nameToStreamCallback =
nullptr;
File entry to minimize RAM usage by using path index and name.
Definition AudioSource.h:154