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();
103 return nextStreamCallback ==
nullptr ? nullptr : nextStreamCallback(offset);
108 LOGI(
"selectStream: %d",
index);
109 if (indexStreamCallback ==
nullptr) {
110 LOGI(
"setCallbackSelectStream not provided");
119 return indexStreamCallback(
index);
124 return indexStreamCallback ==
nullptr ? nullptr : indexStreamCallback(-1);
127 void setCallbackOnStart(
void (*callback)()) { onStartCallback = callback; }
129 void setCallbackNextStream(Stream* (*callback)(
int offset)) {
130 nextStreamCallback = callback;
133 void setCallbackSelectStream(Stream* (*callback)(
int idx)) {
134 indexStreamCallback = callback;
139 virtual void setAutoNext(
bool a) { auto_next = a; }
142 virtual const char*
getPath() {
return path; }
145 void (*onStartCallback)() =
nullptr;
146 bool auto_next =
true;
147 Stream* (*nextStreamCallback)(
int offset) =
nullptr;
148 Stream* (*indexStreamCallback)(
int index) =
nullptr;
149 const char* path =
nullptr;
161 FileEntry(
int pathIdx,
const char* fileName) : path_index(pathIdx) {
171 virtual void addName(
const char* nameWithPath) = 0;
182 : dataSource(dataSource), prefix(prefix) {}
183 void setPrefix(
const char* prefix) { this->prefix = prefix; }
184 size_t write(uint8_t ch)
override {
185 if (ch ==
'\n' || ch ==
'\r') {
187 if (line_buffer.
length() > 0) {
189 if (prefix !=
nullptr) {
193 name.add(line_buffer.
c_str());
194 LOGD(
"adding '%s'", name.c_str());
195 dataSource.addName(name.c_str());
198 LOGD(
"adding '%s'", line_buffer.
c_str());
199 dataSource.addName(line_buffer.
c_str());
201 line_buffer.
clear(
false);
206 line_buffer.
add((
char)ch);
211 size_t write(
const uint8_t* buffer,
size_t size)
override {
212 for (
size_t i = 0; i < size; i++) {
220 if (line_buffer.
length() > 0) {
221 dataSource.addName(line_buffer.
c_str());
228 Str line_buffer{200};
229 const char* prefix =
nullptr;
250template <
typename FileType>
253 typedef FileType* (*FileToStreamCallback)(
const char* path,
260 : nameToStreamCallback(callback) {}
266 current_stream =
nullptr;
273 if (files.empty())
return nullptr;
275 current_index += offset;
277 if (current_index < 0) {
278 current_index = files.size() - 1;
279 }
else if (current_index >= (
int)files.size()) {
289 if (files.empty() || index < 0 || index >= (
int)files.size()) {
290 LOGE(
"Invalid index: %d (size: %d)",
index, files.size());
294 current_index =
index;
296 LOGI(
"selectStream: %d -> %s",
index, fullPath.
c_str());
298 if (nameToStreamCallback) {
300 return current_stream;
303 LOGE(
"No file to stream callback set!");
310 if (path ==
nullptr)
return nullptr;
317 LOGE(
"File not found: %s", path);
322 virtual int index()
override {
return current_index; }
326 if (path ==
nullptr)
return -1;
329 for (
int i = 0; i < (int)files.size(); i++) {
331 if (fullPath.
equals(path)) {
339 void addName(
const char* nameWithPath)
override {
341 if (nameWithPath ==
nullptr)
return;
342 LOGI(
"addName: '%s'", nameWithPath);
345 StrView nameWithPathStr(nameWithPath);
346 int lastSlashPos = nameWithPathStr.
lastIndexOf(
"/");
347 int len = nameWithPathStr.
length();
351 if (lastSlashPos < 0) {
354 nameStr.
set(nameWithPath);
357 pathStr.
substring(nameWithPath, 0, lastSlashPos);
358 nameStr.
substring(nameWithPath, lastSlashPos + 1, len);
366 files.push_back(entry);
373 if (nameWithPath ==
nullptr)
return false;
375 int idx =
indexOf(nameWithPath);
377 LOGI(
"deleteName: '%s' at index %d", nameWithPath, idx);
381 LOGW(
"deleteName: File not found: '%s'", nameWithPath);
388 if (idx >= files.size()) {
389 LOGW(
"deleteIndex: Invalid index: %d (size: %d)", (
int)idx, files.size());
393 LOGI(
"deleteIndex: Removing file at index %d", (
int)idx);
394 files.erase(files.begin() + idx);
397 if (current_index >= (
int)idx) {
399 if (current_index < 0 && !files.empty()) {
408 template <
typename T,
size_t N>
410 for (
size_t i = 0; i < N; i++) {
418 path_registry.clear();
420 current_stream =
nullptr;
424 int size() {
return files.size(); }
431 nameToStreamCallback = callback;
436 if (current_stream) {
437 return *current_stream;
439 static FileType empty;
444 virtual const char*
toStr()
override {
445 if (current_index >= 0 && current_index < (
int)files.size()) {
447 return current_path.
c_str();
458 int current_index = 0;
459 FileType* current_stream =
nullptr;
460 FileToStreamCallback nameToStreamCallback =
nullptr;
465 if (path ==
nullptr) path =
"";
468 for (
int i = 0; i < (int)path_registry.size(); i++) {
469 if (strcmp(path_registry[i].c_str(), path) == 0) {
477 path_registry.push_back(newPath);
478 return path_registry.size() - 1;
486 if (index < 0 || index >= (
int)files.size()) {
494 if (entry.path_index >= 0 && entry.path_index < (
int)path_registry.size()) {
495 result = path_registry[entry.path_index].c_str();
509 if (pathIndex >= 0 && pathIndex < (
int)path_registry.size()) {
510 return path_registry[pathIndex].c_str();
533template <
typename FileType>
536 typedef FileType* (*FileToStreamCallback)(
const char* path, FileType& file);
543 : file_array(nameArray), array_size(N), nameToStreamCallback(callback) {}
547 FileToStreamCallback callback)
548 : file_array(nameArray),
550 nameToStreamCallback(callback) {}
556 current_stream =
nullptr;
563 if (array_size == 0)
return nullptr;
565 current_index += offset;
567 if (current_index < 0) {
568 current_index = array_size - 1;
569 }
else if (current_index >= (
int)array_size) {
579 if (array_size == 0 || index < 0 || index >= (
int)array_size) {
580 LOGE(
"Invalid index: %d (size: %d)",
index, array_size);
584 current_index =
index;
585 const char* filePath = file_array[
index];
586 LOGI(
"selectStream: %d -> %s",
index, filePath);
588 if (nameToStreamCallback && filePath) {
589 current_stream = nameToStreamCallback(filePath, getCurrentFile());
590 return current_stream;
593 LOGE(
"No file to stream callback set or invalid file path!");
600 if (path ==
nullptr)
return nullptr;
607 LOGE(
"File not found: %s", path);
612 virtual int index()
override {
return current_index; }
616 if (path ==
nullptr)
return -1;
619 for (
int i = 0; i < (int)array_size; i++) {
620 const char* filePath = file_array[i];
631 file_array = nameArray;
638 file_array = nameArray;
644 int size()
const {
return array_size; }
647 bool isEmpty()
const {
return array_size == 0; }
651 nameToStreamCallback = callback;
654 FileType& getCurrentFile() {
655 if (current_stream) {
656 return *current_stream;
658 static FileType empty;
664 if (
index >= 0 &&
index < (
int)array_size && file_array) {
665 return file_array[
index];
671 virtual const char*
toStr()
override {
672 if (current_index >= 0 && current_index < (
int)array_size && file_array) {
673 return file_array[current_index];
682 const char*
const* file_array =
nullptr;
683 size_t array_size = 0;
684 int current_index = 0;
685 FileType* current_stream =
nullptr;
686 FileToStreamCallback nameToStreamCallback =
nullptr;
File entry to minimize RAM usage by using path index and name.
Definition AudioSource.h:155