arduino-audio-tools
Loading...
Searching...
No Matches
AudioSourceZephyr.h
Go to the documentation of this file.
1#pragma once
2
3#ifndef IS_ZEPHYR
4# error("ZephyrSD only supported by zephyr")
5#endif
6
7#include "AudioLogger.h"
10#include "ZephyrFile.h"
11#include "ZephyrSD.h"
12
13#include <zephyr/fs/fs.h>
14
15#ifndef FS_MAX_PATH
16# define FS_MAX_PATH 256
17#endif
18
19namespace audio_tools {
20
32public:
33
34 AudioSourceZephyr(const char *mountPoint = "/SD",
35 const char *ext = ".mp3") {
36
37 mount_point = mountPoint ? mountPoint : "/";
39 extension = ext ? ext : "";
40
42 }
43
45 end();
46 }
47
48 // ------------------------------------------------------------
49 // lifecycle
50 // ------------------------------------------------------------
51
52 bool begin() override {
53 TRACED();
54
55 if (!isMounted()) {
56 LOGE("Filesystem not mounted: %s", mount_point);
57 return false;
58 }
59
60 idx_pos = 0;
61 count = 0;
62 return true;
63 }
64
65 void end() {
66 closeFile();
67 }
68
69 // ------------------------------------------------------------
70 // playback control
71 // ------------------------------------------------------------
72
73 Stream *nextStream(int offset = 1) override {
74 LOGI("nextStream: %d", offset);
75
76 Stream *s = selectStream(idx_pos + offset);
77
78 if (!s && offset > 0) {
79 LOGI("wrap to start");
80 idx_pos = 0;
82 }
83
84 return s;
85 }
86
87 Stream *selectStream(int index) override {
88
89 long cnt = size();
90
91 if (cnt <= 0) {
92 LOGW("No audio files in: %s", start_path);
93 return nullptr;
94 }
95
96 int norm = index % cnt;
97 if (norm < 0) norm += cnt;
98
99 idx_pos = norm;
100
101 const char *path = get(norm);
102 if (!path) {
103 LOGW("Invalid index: %d", norm);
104 return nullptr;
105 }
106
107 LOGI("Playing: %s", path);
108
109 closeFile();
110 return openFile(path);
111 }
112
113 Stream *selectStream(const char *path) override {
114 LOGI("selectStream(path): %s", path);
115
116 closeFile();
117 return openFile(path);
118 }
119
120 // ------------------------------------------------------------
121 // configuration
122 // ------------------------------------------------------------
123
124 void setFileFilter(const char *filter) {
125 file_name_pattern = filter ? filter : "*";
126 }
127
128 void setPath(const char *p) {
129 start_path = p ? p : "/";
130 }
131
132 int index() const {
133 return idx_pos;
134 }
135
136 const char *toStr() const {
137 return current_path[0] ? current_path : nullptr;
138 }
139
140 bool isAutoNext() override {
141 return true;
142 }
143
144 // ------------------------------------------------------------
145 // file enumeration
146 // ------------------------------------------------------------
147
148 long size(bool force_rescan = false) {
149
150 if (force_rescan) {
151 count = 0;
152 }
153
154 if (count == 0) {
156 }
157
158 return count;
159 }
160
161protected:
162
163 // ------------------------------------------------------------
164 // state
165 // ------------------------------------------------------------
166
168
169 size_t idx_pos = 0;
170 long count = 0;
171
172 char current_path[FS_MAX_PATH + 1] = {};
173
174 const char *extension = ".mp3";
175 const char *start_path = "/";
176 const char *file_name_pattern = "*";
177 const char *mount_point = "/SD";
178
179 // ------------------------------------------------------------
180 // mount check ONLY (no ownership)
181 // ------------------------------------------------------------
182
183 bool isMounted() const {
184 struct fs_dir_t dir;
186 return fs_opendir(&dir, mount_point) == 0;
187 }
188
189 // ------------------------------------------------------------
190 // file handling
191 // ------------------------------------------------------------
192
193 void closeFile() {
195 current_path[0] = '\0';
196 }
197
198 Stream *openFile(const char *path) {
199 if (!path) return nullptr;
200
201 closeFile();
202
203 strncpy(current_path, path, sizeof(current_path) - 1);
204 current_path[sizeof(current_path) - 1] = '\0';
205
207 return &file_stream;
208 }
209
210 LOGE("Failed to open: %s", current_path);
211 return nullptr;
212 }
213
214 // ------------------------------------------------------------
215 // directory traversal
216 // ------------------------------------------------------------
217
218 const char *get(int idx) {
219 int running = 0;
220 return scanForIndex(start_path, idx, running);
221 }
222
223 const char *scanForIndex(const char *path,
224 int target,
225 int &running) {
226
227 struct fs_dir_t dir;
229
230 if (fs_opendir(&dir, path) != 0) {
231 return nullptr;
232 }
233
234 struct fs_dirent entry;
235 const char *result = nullptr;
236
237 while (true) {
238 int rc = fs_readdir(&dir, &entry);
239 if (rc != 0 || entry.name[0] == '\0') break;
240
241 char full[FS_MAX_PATH + 2];
242
243 if (snprintf(full, sizeof(full),
244 "%s/%s", path, entry.name) >= (int)sizeof(full)) {
245 continue;
246 }
247
248 if (entry.type == FS_DIR_ENTRY_DIR) {
249 result = scanForIndex(full, target, running);
250 if (result) break;
251 }
252 else if (isValidAudioFile(entry.name)) {
253
254 if (running == target) {
255 strncpy(current_path, full,
256 sizeof(current_path) - 1);
257 current_path[sizeof(current_path) - 1] = '\0';
258
259 result = current_path;
260 break;
261 }
262
263 running++;
264 }
265 }
266
268 return result;
269 }
270
271 void scanCount(const char *path) {
272
273 struct fs_dir_t dir;
275
276 if (fs_opendir(&dir, path) != 0) {
277 return;
278 }
279
280 struct fs_dirent entry;
281
282 while (true) {
283 int rc = fs_readdir(&dir, &entry);
284 if (rc != 0 || entry.name[0] == '\0') break;
285
286 char full[FS_MAX_PATH + 2];
287
288 if (snprintf(full, sizeof(full),
289 "%s/%s", path, entry.name) >= (int)sizeof(full)) {
290 continue;
291 }
292
293 if (entry.type == FS_DIR_ENTRY_DIR) {
294 scanCount(full);
295 }
296 else if (isValidAudioFile(entry.name)) {
297 count++;
298 }
299 }
300
302 }
303
304 // ------------------------------------------------------------
305 // filtering
306 // ------------------------------------------------------------
307
308 bool isValidAudioFile(const char *name) {
309
310 if (!name || !extension) return false;
311
312 StrView fname(name);
313
314 return fname.endsWithIgnoreCase(extension)
315 && fname.matches(file_name_pattern);
316 }
317};
318
319} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define FS_MAX_PATH
Definition AudioSourceZephyr.h:16
Definition Arduino.h:136
Abstract Audio Data Source for the AudioPlayer which is used by the Audio Players.
Definition AudioSource.h:17
int timeout_auto_next_value
Definition AudioSource.h:76
AudioSource using Zephyr FS API (NO mounting, only uses mounted FS). Mount using the ZephyrSD class.
Definition AudioSourceZephyr.h:31
Stream * openFile(const char *path)
Definition AudioSourceZephyr.h:198
const char * get(int idx)
Definition AudioSourceZephyr.h:218
Stream * selectStream(const char *path) override
Returns audio stream by path: The index is not changed!
Definition AudioSourceZephyr.h:113
const char * toStr() const
Definition AudioSourceZephyr.h:136
Stream * selectStream(int index) override
Definition AudioSourceZephyr.h:87
const char * extension
Definition AudioSourceZephyr.h:174
Stream * nextStream(int offset=1) override
Returns next audio stream.
Definition AudioSourceZephyr.h:73
AudioSourceZephyr(const char *mountPoint="/SD", const char *ext=".mp3")
Definition AudioSourceZephyr.h:34
const char * scanForIndex(const char *path, int target, int &running)
Definition AudioSourceZephyr.h:223
void scanCount(const char *path)
Definition AudioSourceZephyr.h:271
long count
Definition AudioSourceZephyr.h:170
size_t idx_pos
Definition AudioSourceZephyr.h:169
const char * mount_point
Definition AudioSourceZephyr.h:177
const char * start_path
Definition AudioSourceZephyr.h:175
void end()
Definition AudioSourceZephyr.h:65
void setPath(const char *p)
Definition AudioSourceZephyr.h:128
bool isMounted() const
Definition AudioSourceZephyr.h:183
void closeFile()
Definition AudioSourceZephyr.h:193
long size(bool force_rescan=false)
Definition AudioSourceZephyr.h:148
~AudioSourceZephyr()
Definition AudioSourceZephyr.h:44
ZephyrFile file_stream
Definition AudioSourceZephyr.h:167
bool begin() override
Reset actual stream and move to root.
Definition AudioSourceZephyr.h:52
int index() const
Definition AudioSourceZephyr.h:132
void setFileFilter(const char *filter)
Definition AudioSourceZephyr.h:124
bool isValidAudioFile(const char *name)
Definition AudioSourceZephyr.h:308
char current_path[256+1]
Definition AudioSourceZephyr.h:172
const char * file_name_pattern
Definition AudioSourceZephyr.h:176
bool isAutoNext() override
Returns default setting go to the next.
Definition AudioSourceZephyr.h:140
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual bool matches(const char *pattern)
Definition StrView.h:193
virtual bool endsWithIgnoreCase(const char *str)
checks if the string ends with the indicated substring
Definition StrView.h:185
Arduino File API for Zephyr.
Definition ZephyrFile.h:23
void close()
Definition ZephyrFile.h:67
bool open(const char *file_path, fs_mode_t mode=FS_O_READ)
Definition ZephyrFile.h:44
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:508