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),
66 virtual void setAutoNext(
bool flag) { is_auto_next = flag; }
72 virtual const char*
toStr() {
return nullptr; }
75 int timeout_auto_next_value = 500;
76 bool is_auto_next =
true;
90 void (*onStartCallback)() =
nullptr) {
92 this->onStartCallback = onStartCallback;
93 this->nextStreamCallback = nextStreamCallback;
99 if (onStartCallback !=
nullptr) onStartCallback();
107 return nextStreamCallback ==
nullptr ? nullptr : nextStreamCallback(offset);
112 LOGI(
"selectStream: %d",
index);
113 if (indexStreamCallback ==
nullptr) {
114 LOGI(
"setCallbackSelectStream not provided");
123 return indexStreamCallback(
index);
128 return indexStreamCallback ==
nullptr ? nullptr : indexStreamCallback(-1);
131 void setCallbackOnStart(
void (*callback)()) { onStartCallback = callback; }
133 void setCallbackNextStream(Stream* (*callback)(
int offset)) {
134 nextStreamCallback = callback;
137 void setCallbackSelectStream(Stream* (*callback)(
int idx)) {
138 indexStreamCallback = callback;
143 virtual void setAutoNext(
bool a) { auto_next = a; }
146 virtual const char*
getPath() {
return path; }
149 void (*onStartCallback)() =
nullptr;
150 bool auto_next =
true;
151 Stream* (*nextStreamCallback)(
int offset) =
nullptr;
152 Stream* (*indexStreamCallback)(
int index) =
nullptr;
153 const char* path =
nullptr;
165 FileEntry(
int pathIdx,
const char* fileName) : path_index(pathIdx) {
175 virtual void addName(
const char* nameWithPath) = 0;
186 : dataSource(dataSource), prefix(prefix) {}
187 void setPrefix(
const char* prefix) { this->prefix = prefix; }
188 size_t write(uint8_t ch)
override {
189 if (ch ==
'\n' || ch ==
'\r') {
191 if (line_buffer.
length() > 0) {
193 if (prefix !=
nullptr) {
197 name.add(line_buffer.
c_str());
198 LOGD(
"adding '%s'", name.c_str());
199 dataSource.addName(name.c_str());
202 LOGD(
"adding '%s'", line_buffer.
c_str());
203 dataSource.addName(line_buffer.
c_str());
205 line_buffer.
clear(
false);
210 line_buffer.
add((
char)ch);
215 size_t write(
const uint8_t* buffer,
size_t size)
override {
216 for (
size_t i = 0; i < size; i++) {
224 if (line_buffer.
length() > 0) {
225 dataSource.addName(line_buffer.
c_str());
232 Str line_buffer{200};
233 const char* prefix =
nullptr;
254template <
typename FileType>
257 typedef FileType* (*FileToStreamCallback)(
const char* path,
264 : nameToStreamCallback(callback) {}
270 current_stream =
nullptr;
277 if (files.empty())
return nullptr;
279 current_index += offset;
281 if (current_index < 0) {
282 current_index = files.size() - 1;
283 }
else if (current_index >= (
int)files.size()) {
293 if (files.empty() || index < 0 || index >= (
int)files.size()) {
294 LOGE(
"Invalid index: %d (size: %d)",
index, files.size());
298 current_index =
index;
300 LOGI(
"selectStream: %d -> %s",
index, fullPath.
c_str());
302 if (nameToStreamCallback) {
304 return current_stream;
307 LOGE(
"No file to stream callback set!");
314 if (path ==
nullptr)
return nullptr;
321 LOGE(
"File not found: %s", path);
326 virtual int index()
override {
return current_index; }
330 if (path ==
nullptr)
return -1;
333 for (
int i = 0; i < (int)files.size(); i++) {
335 if (fullPath.
equals(path)) {
343 void addName(
const char* nameWithPath)
override {
345 if (nameWithPath ==
nullptr)
return;
346 LOGI(
"addName: '%s'", nameWithPath);
349 StrView nameWithPathStr(nameWithPath);
350 int lastSlashPos = nameWithPathStr.
lastIndexOf(
"/");
351 int len = nameWithPathStr.
length();
355 if (lastSlashPos < 0) {
358 nameStr.
set(nameWithPath);
361 pathStr.
substring(nameWithPath, 0, lastSlashPos);
362 nameStr.
substring(nameWithPath, lastSlashPos + 1, len);
370 files.push_back(entry);
377 if (nameWithPath ==
nullptr)
return false;
379 int idx =
indexOf(nameWithPath);
381 LOGI(
"deleteName: '%s' at index %d", nameWithPath, idx);
385 LOGW(
"deleteName: File not found: '%s'", nameWithPath);
392 if (idx >= files.size()) {
393 LOGW(
"deleteIndex: Invalid index: %d (size: %d)", (
int)idx, files.size());
397 LOGI(
"deleteIndex: Removing file at index %d", (
int)idx);
398 files.erase(files.begin() + idx);
401 if (current_index >= (
int)idx) {
403 if (current_index < 0 && !files.empty()) {
412 template <
typename T,
size_t N>
414 for (
size_t i = 0; i < N; i++) {
422 path_registry.clear();
424 current_stream =
nullptr;
428 int size() {
return files.size(); }
435 nameToStreamCallback = callback;
440 if (current_stream) {
441 return *current_stream;
443 static FileType empty;
448 virtual const char*
toStr()
override {
449 if (current_index >= 0 && current_index < (
int)files.size()) {
451 return current_path.
c_str();
462 int current_index = 0;
463 FileType* current_stream =
nullptr;
464 FileToStreamCallback nameToStreamCallback =
nullptr;
469 if (path ==
nullptr) path =
"";
472 for (
int i = 0; i < (int)path_registry.size(); i++) {
473 if (strcmp(path_registry[i].c_str(), path) == 0) {
481 path_registry.push_back(newPath);
482 return path_registry.size() - 1;
490 if (index < 0 || index >= (
int)files.size()) {
498 if (entry.path_index >= 0 && entry.path_index < (
int)path_registry.size()) {
499 result = path_registry[entry.path_index].c_str();
513 if (pathIndex >= 0 && pathIndex < (
int)path_registry.size()) {
514 return path_registry[pathIndex].c_str();
537template <
typename FileType>
540 typedef FileType* (*FileToStreamCallback)(
const char* path, FileType& file);
547 : file_array(nameArray), array_size(N), nameToStreamCallback(callback) {}
551 FileToStreamCallback callback)
552 : file_array(nameArray),
554 nameToStreamCallback(callback) {}
560 current_stream =
nullptr;
567 if (array_size == 0)
return nullptr;
569 current_index += offset;
571 if (current_index < 0) {
572 current_index = array_size - 1;
573 }
else if (current_index >= (
int)array_size) {
583 if (array_size == 0 || index < 0 || index >= (
int)array_size) {
584 LOGE(
"Invalid index: %d (size: %d)",
index, array_size);
588 current_index =
index;
589 const char* filePath = file_array[
index];
590 LOGI(
"selectStream: %d -> %s",
index, filePath);
592 if (nameToStreamCallback && filePath) {
593 current_stream = nameToStreamCallback(filePath, getCurrentFile());
594 return current_stream;
597 LOGE(
"No file to stream callback set or invalid file path!");
604 if (path ==
nullptr)
return nullptr;
611 LOGE(
"File not found: %s", path);
616 virtual int index()
override {
return current_index; }
620 if (path ==
nullptr)
return -1;
623 for (
int i = 0; i < (int)array_size; i++) {
624 const char* filePath = file_array[i];
635 file_array = nameArray;
642 file_array = nameArray;
648 int size()
const {
return array_size; }
651 bool isEmpty()
const {
return array_size == 0; }
655 nameToStreamCallback = callback;
658 FileType& getCurrentFile() {
659 if (current_stream) {
660 return *current_stream;
662 static FileType empty;
668 if (
index >= 0 &&
index < (
int)array_size && file_array) {
669 return file_array[
index];
675 virtual const char*
toStr()
override {
676 if (current_index >= 0 && current_index < (
int)array_size && file_array) {
677 return file_array[current_index];
686 const char*
const* file_array =
nullptr;
687 size_t array_size = 0;
688 int current_index = 0;
689 FileType* current_stream =
nullptr;
690 FileToStreamCallback nameToStreamCallback =
nullptr;
File entry to minimize RAM usage by using path index and name.
Definition AudioSource.h:159