arduino-audio-tools
Loading...
Searching...
No Matches
AudioStreams.h
1#pragma once
2#include "AudioTools/CoreAudio/AudioEffects/SoundGenerator.h"
3#include "AudioTools/CoreAudio/AudioLogger.h"
4#include "AudioTools/CoreAudio/AudioOutput.h"
5#include "AudioTools/CoreAudio/AudioTimer/AudioTimer.h"
6#include "AudioTools/CoreAudio/AudioTypes.h"
7#include "AudioTools/CoreAudio/BaseConverter.h"
8#include "AudioTools/CoreAudio/BaseStream.h"
9#include "AudioTools/CoreAudio/Buffers.h"
10#include "AudioToolsConfig.h"
11
12#ifndef IRAM_ATTR
13#define IRAM_ATTR
14#endif
15
16namespace audio_tools {
17
24 public:
26 TRACED();
27 p_stream = &s;
28 p_stream->setTimeout(clientTimeout);
29 }
30
31 virtual bool begin() { return true; }
32 virtual void end() {}
33
34 virtual size_t readBytes(uint8_t *data, size_t len) {
35 // Serial.print("Timeout audiostream: ");
36 // Serial.println(p_stream->getTimeout());
37 return p_stream->readBytes(data, len);
38 }
39
40 int read() { return p_stream->read(); }
41
42 int peek() { return p_stream->peek(); }
43
44 int available() { return p_stream->available(); }
45
46 virtual size_t write(uint8_t c) { return p_stream->write(c); }
47
48 virtual size_t write(const uint8_t *data, size_t len) {
49 return p_stream->write(data, len);
50 }
51
52 virtual int availableForWrite() { return p_stream->availableForWrite(); }
53
54 virtual void flush() { p_stream->flush(); }
55
56 protected:
57 Stream *p_stream;
58 int32_t clientTimeout = URL_CLIENT_TIMEOUT; // 60000;
59};
60
69 public:
71 virtual void setStream(Stream &in) = 0;
73 virtual void setOutput(Print &out) = 0;
74};
75
83class MemoryStream : public AudioStream {
84 public:
85 // Default constructor
86 MemoryStream() = default;
88 MemoryStream(int buffer_size, MemoryType memoryType) {
89 LOGD("MemoryStream: %d", buffer_size);
90 this->buffer_size = buffer_size;
91 this->memory_type = memoryType;
92 resize(buffer_size);
93 info.clear(); // mark audio info as unknown
94 }
95
98 MemoryStream(const uint8_t *buffer, int buffer_size, bool isActive = true,
99 MemoryType memoryType = FLASH_RAM) {
100 LOGD("MemoryStream: %d", buffer_size);
101 setValue(buffer, buffer_size, memoryType);
102 is_active = isActive;
103 info.clear(); // mark audio info as unknown
104 }
105
107 MemoryStream(MemoryStream &source) : AudioStream() { copy(source); }
108
111 setValue(source.buffer, source.buffer_size, source.memory_type);
112 // clear source data
113 source.setValue(nullptr, 0, source.memory_type);
114 }
115
116 ~MemoryStream() {
117 TRACED();
118 if (memoryCanChange() && buffer != nullptr) free(buffer);
119 }
120
123 copy(other);
124 return *this;
125 }
126
128 operator bool() override { return available() > 0; }
129
131 bool begin(AudioInfo info) {
132 this->info = info;
133 return begin();
134 }
135
137 bool begin() override {
138 TRACED();
139 write_pos = memoryCanChange() ? 0 : buffer_size;
140 if (this->buffer == nullptr && memoryCanChange()) {
141 resize(buffer_size);
142 }
143 read_pos = 0;
144 is_active = true;
145 return true;
146 }
147
148 virtual size_t write(uint8_t byte) override {
149 if (!is_active) return 0;
150 if (memory_type == FLASH_RAM) return 0;
151 if (buffer == nullptr) return 0;
152 int result = 0;
153 if (write_pos < buffer_size) {
154 result = 1;
155 buffer[write_pos] = byte;
156 write_pos++;
157 }
158 return result;
159 }
160
161 virtual size_t write(const uint8_t *data, size_t len) override {
162 if (!is_active) return 0;
163 if (memory_type == FLASH_RAM) return 0;
164 size_t result = 0;
165 for (size_t j = 0; j < len; j++) {
166 if (!write(data[j])) {
167 break;
168 }
169 result = j + 1;
170 }
171 return result;
172 }
173
174 virtual int available() override {
175 if (!is_active) return 0;
176 if (buffer == nullptr) return 0;
177 int result = write_pos - read_pos;
178 if (result <= 0 && is_loop) {
179 // rewind to start
180 read_pos = rewind_pos;
181 result = write_pos - read_pos;
182 // call callback
183 if (rewind != nullptr) rewind();
184 }
185 return is_loop ? DEFAULT_BUFFER_SIZE : result;
186 }
187
188 virtual int availableForWrite() override {
189 if (!is_active) return 0;
190 if (memory_type == FLASH_RAM) return 0;
191 return buffer_size - write_pos;
192 }
193
194 virtual int read() override {
195 int result = peek();
196 if (result >= 0) {
197 read_pos++;
198 }
199 return result;
200 }
201
202 virtual size_t readBytes(uint8_t *data, size_t len) override {
203 if (!is_active) return 0;
204 size_t count = 0;
205 while (count < len) {
206 int c = read();
207 if (c < 0) break;
208 *data++ = (char)c;
209 count++;
210 }
211 return count;
212 }
213
214 virtual int peek() override {
215 if (!is_active) return -1;
216 int result = -1;
217 if (available() > 0) {
218 result = buffer[read_pos];
219 }
220 return result;
221 }
222
223 virtual void flush() override {}
224
225 virtual void end() override {
226 read_pos = 0;
227 is_active = false;
228 }
229
231 virtual void clear(bool reset = false) {
232 if (memoryCanChange()) {
233 write_pos = 0;
234 read_pos = 0;
235 if (buffer == nullptr) {
236 resize(buffer_size);
237 }
238 if (reset) {
239 // we clear the buffer data
240 memset(buffer, 0, buffer_size);
241 }
242 } else {
243 read_pos = 0;
244 LOGW("data is read only");
245 }
246 }
247
250 virtual void setLoop(bool loop) {
251 is_loop = loop;
252 rewind_pos = 0;
253 if (buffer != nullptr && buffer_size > 12) {
254 if (memcmp("WAVE", buffer + 8, 4) == 0) {
255 rewind_pos = 44;
256 }
257 }
258 }
259
261 virtual void setLoop(bool loop, int rewindPos) {
262 is_loop = loop;
263 rewind_pos = rewindPos;
264 }
265
268 virtual bool resize(size_t size) {
269 if (!memoryCanChange()) return false;
270
271 buffer_size = size;
272 switch (memory_type) {
273#if defined(ESP32) && defined(ARDUINO)
274 case PS_RAM:
275 buffer = (buffer == nullptr) ? (uint8_t *)ps_calloc(size, 1)
276 : (uint8_t *)ps_realloc(buffer, size);
277 break;
278#endif
279 default:
280 buffer = (buffer == nullptr) ? (uint8_t *)calloc(size, 1)
281 : (uint8_t *)realloc(buffer, size);
282 break;
283 }
284 return buffer != nullptr;
285 }
286
288 virtual uint8_t *data() { return buffer; }
289
291 virtual void setAvailable(size_t len) { this->write_pos = len; }
292
294 void setRewindCallback(void (*cb)()) { this->rewind = cb; }
295
297 void setValue(const uint8_t *buffer, int buffer_size,
298 MemoryType memoryType = FLASH_RAM) {
299 this->buffer_size = buffer_size;
300 this->read_pos = 0;
301 this->write_pos = buffer_size;
302 this->buffer = (uint8_t *)buffer;
303 this->memory_type = memoryType;
304 }
305
306 protected:
307 int write_pos = 0;
308 int read_pos = 0;
309 int buffer_size = 0;
310 int rewind_pos = 0;
311 uint8_t *buffer = nullptr;
312 MemoryType memory_type = RAM;
313 bool is_loop = false;
314 void (*rewind)() = nullptr;
315 bool is_active = false;
316
317 bool memoryCanChange() { return memory_type != FLASH_RAM; }
318
319 void copy(MemoryStream &source) {
320 if (this == &source) return;
321 if (source.memory_type == FLASH_RAM) {
322 setValue(source.buffer, source.buffer_size, source.memory_type);
323 } else {
324 setValue(nullptr, source.buffer_size, source.memory_type);
325 resize(buffer_size);
326 memcpy(buffer, source.buffer, buffer_size);
327 }
328 }
329};
330
339 public:
340 RingBufferStream(int size = DEFAULT_BUFFER_SIZE) { resize(size); }
341
342 virtual int available() override {
343 // LOGD("RingBufferStream::available: %zu",buffer->available());
344 return buffer.available();
345 }
346
347 virtual int availableForWrite() override {
348 return buffer.availableForWrite();
349 }
350
351 virtual void flush() override {}
352 virtual int peek() override {
353 uint8_t data = 0;
354 if (!buffer.peek(data)) return -1;
355 return data;
356 }
357 virtual int read() override {
358 uint8_t data = 0;
359 if (!buffer.read(data)) return -1;
360 return data;
361 }
362
363 virtual size_t readBytes(uint8_t *data, size_t len) override {
364 return buffer.readArray(data, len);
365 }
366
367 virtual size_t write(const uint8_t *data, size_t len) override {
368 // LOGD("RingBufferStream::write: %zu",len);
369 return buffer.writeArray(data, len);
370 }
371
372 virtual size_t write(uint8_t c) override { return buffer.write(c); }
373
374 void resize(int size) { buffer.resize(size); }
375
376 size_t size() { return buffer.size(); }
377
378 protected:
379 RingBuffer<uint8_t> buffer{0};
380};
381
393template <class T = int16_t>
395 public:
396 GeneratedSoundStream() = default;
397
399 TRACED();
400 setInput(generator);
401 }
402
403 void setInput(SoundGenerator<T> &generator) {
404 this->generator_ptr = &generator;
405 }
406
407 AudioInfo defaultConfig() { return this->generator_ptr->defaultConfig(); }
408
409 void setAudioInfo(AudioInfo newInfo) override {
410 if (newInfo.bits_per_sample != sizeof(T) * 8) {
411 LOGE("Wrong bits_per_sample: %d", newInfo.bits_per_sample);
412 }
414 }
415
417 bool begin() override {
418 TRACED();
419 if (generator_ptr == nullptr) {
420 LOGE("%s", source_not_defined_error);
421 return false;
422 }
423 generator_ptr->begin();
424 notifyAudioChange(generator_ptr->audioInfo());
425 active = true;
426 return active;
427 }
428
430 bool begin(AudioInfo cfg) {
431 TRACED();
432 if (generator_ptr == nullptr) {
433 LOGE("%s", source_not_defined_error);
434 return false;
435 }
436 generator_ptr->begin(cfg);
437 notifyAudioChange(generator_ptr->audioInfo());
438 active = true;
439 return active;
440 }
441
443 void end() override {
444 TRACED();
445 generator_ptr->end();
446 active = true; // legacy support - most sketches do not call begin
447 }
448
449 AudioInfo audioInfo() override { return generator_ptr->audioInfo(); }
450
452 virtual int available() override {
453 return active ? DEFAULT_BUFFER_SIZE * 2 : 0;
454 }
455
457 size_t readBytes(uint8_t *data, size_t len) override {
458 if (!active) return 0;
459 LOGD("GeneratedSoundStream::readBytes: %u", (unsigned int)len);
460 return generator_ptr->readBytes(data, len);
461 }
462
463 bool isActive() { return active && generator_ptr->isActive(); }
464
465 operator bool() override { return isActive(); }
466
467 void flush() override {}
468
469 protected:
470 bool active = true; // support for legacy sketches
471 SoundGenerator<T> *generator_ptr;
472 const char *source_not_defined_error = "Source not defined";
473};
474
484 public:
485 BufferedStream(size_t buffer_size) {
486 TRACED();
487 if (buffer_size > 0) resize(buffer_size);
488 }
489
490 BufferedStream(Print &out, size_t buffer_size = 1024) {
491 TRACED();
492 setOutput(out);
493 if (buffer_size > 0) resize(buffer_size);
494 }
495
496 BufferedStream(Stream &io, size_t buffer_size = 1024) {
497 TRACED();
498 setStream(io);
499 if (buffer_size > 0) resize(buffer_size);
500 }
501
502 BufferedStream(size_t buffer_size, Print &out) {
503 TRACED();
504 setOutput(out);
505 if (buffer_size > 0) resize(buffer_size);
506 }
507
508 BufferedStream(size_t buffer_size, Stream &io) {
509 TRACED();
510 setStream(io);
511 if (buffer_size > 0) resize(buffer_size);
512 }
513
514 void setOutput(Print &out) override { p_out = &out; }
515 void setStream(Print &out) { setOutput(out); }
516 void setStream(Stream &io) override {
517 p_in = &io;
518 p_out = &io;
519 }
520
522 size_t write(uint8_t c) override {
523 if (buffer.isFull()) {
524 flush();
525 }
526 return buffer.write(c);
527 }
528
530 size_t write(const uint8_t *data, size_t len) override {
531 LOGD("%s: %zu", LOG_METHOD, len);
532 int result = 0;
533 for (int j = 0; j < len; j++) {
534 result += write(data[j]);
535 }
536 return result;
537 }
538
540 void flush() override {
541 // just dump the memory of the buffer and clear it
542 if (buffer.available() > 0) {
543 writeExt(buffer.address(), buffer.available());
544 buffer.reset();
545 }
546 }
547
549 int read() override {
550 if (buffer.isEmpty()) {
551 refill();
552 }
553 uint8_t result = 0;
554 if (!buffer.read(result)) return -1;
555 return result;
556 }
557
559 int peek() override {
560 if (buffer.isEmpty()) {
561 refill();
562 }
563 uint8_t result = 0;
564 if (!buffer.peek(result)) return -1;
565 return result;
566 };
567
569 size_t readBytes(uint8_t *data, size_t len) override {
570 if (buffer.isEmpty() && len >= minReadBufferSize) {
571 return readExt(data, len);
572 } else {
573 refill(len);
574 return buffer.readArray(data, len);
575 }
576 }
577
579 size_t peekBytes(uint8_t *data, size_t len) {
580 if (buffer.isEmpty()) {
581 refill();
582 }
583 return buffer.peekArray(data, len);
584 }
585
587 int available() override {
588 if (p_in == nullptr) return 0;
589 return buffer.available() + p_in->available();
590 }
591
593 void clear() { buffer.reset(); }
594
596 void resize(int size) { buffer.resize(size); }
597
599 void setMinUnbufferedReadSize(size_t size) {
600 minReadBufferSize = size;
601 }
602
603 protected:
604 SingleBuffer<uint8_t> buffer{0};
605 Print *p_out = nullptr;
606 Stream *p_in = nullptr;
607 size_t minReadBufferSize = 1024;
608
610 void refill() {
611 // Preserve any existing unread data then append new bytes
612 buffer.trim();
613 size_t already_available = buffer.available();
614 size_t free_space = buffer.availableForWrite();
615 if (free_space == 0) {
616 // Buffer full – nothing we can append
617 return;
618 }
619 // Read new data directly behind existing bytes
620 size_t added = readExt(buffer.address() + already_available, free_space);
621 buffer.setAvailable(already_available + added);
622 }
623
625 void refill(size_t len) {
626 if (buffer.available() >= len) return;
627 refill();
628 }
629
630 virtual size_t writeExt(const uint8_t *data, size_t len) {
631 return p_out == nullptr ? 0 : p_out->write(data, len);
632 }
633 virtual size_t readExt(uint8_t *data, size_t len) {
634 return p_in == nullptr ? 0 : p_in->readBytes(data, len);
635 }
636};
637
646template <typename T>
648 public:
649 ConverterStream() = default;
650
651 ConverterStream(BaseConverter &converter) { setConverter(converter); }
652
653 ConverterStream(Stream &stream, BaseConverter &converter) {
654 setConverter(converter);
655 setStream(stream);
656 }
657
658 ConverterStream(Print &out, BaseConverter &converter) {
659 setConverter(converter);
660 setOutput(out);
661 }
662
663 void setStream(Stream &stream) {
664 TRACEI();
665 p_stream = &stream;
666 p_out = &stream;
667 }
668
669 void setOutput(Print &out) {
670 TRACEI();
671 p_out = &out;
672 }
673
674 void setConverter(BaseConverter &cnv) { p_converter = &cnv; }
675
676 virtual int availableForWrite() { return p_out->availableForWrite(); }
677
678 virtual size_t write(const uint8_t *data, size_t len) {
679 size_t result = p_converter->convert((uint8_t *)data, len);
680 if (result > 0) {
681 size_t result_written = p_out->write(data, result);
682 return len * result_written / result;
683 }
684 return 0;
685 }
686
687 size_t readBytes(uint8_t *data, size_t len) override {
688 if (p_stream == nullptr) return 0;
689 size_t result = p_stream->readBytes(data, len);
690 return p_converter->convert(data, result);
691 }
692
694 virtual int available() override {
695 if (p_stream == nullptr) return 0;
696 return p_stream->available();
697 }
698
699 protected:
700 Stream *p_stream = nullptr;
701 Print *p_out = nullptr;
702 BaseConverter *p_converter;
703};
704
712 public:
713 MeasuringStream(int count = 10, Print *logOut = nullptr) {
714 this->count = count;
715 this->max_count = count;
716 p_stream = &null;
717 p_print = &null;
718 start_time = millis();
719 p_logout = logOut;
720 }
721
722 MeasuringStream(Print &print, int count = 10, Print *logOut = nullptr) {
723 this->count = count;
724 this->max_count = count;
725 setOutput(print);
726 start_time = millis();
727 p_logout = logOut;
728 }
729
730 MeasuringStream(Stream &stream, int count = 10, Print *logOut = nullptr) {
731 this->count = count;
732 this->max_count = count;
733 setStream(stream);
734 start_time = millis();
735 p_logout = logOut;
736 }
737
739 void setLogOutput(Print &out) { p_logout = &out; }
740
742 void setStream(Stream &io) override {
743 p_print = &io;
744 p_stream = &io;
745 };
746
748 void setOutput(Print &out) override { p_print = &out; }
749
751 size_t readBytes(uint8_t *data, size_t len) override {
752 total_bytes_since_begin += len;
753 return measure(p_stream->readBytes(data, len));
754 }
755
756 int available() override { return p_stream->available(); }
757
759 virtual size_t write(const uint8_t *data, size_t len) override {
760 total_bytes_since_begin += len;
761 return measure(p_print->write(data, len));
762 }
763
765 virtual int availableForWrite() override {
766 return p_print->availableForWrite();
767 }
768
770 int bytesPerSecond() { return bytes_per_second; }
771
774 if (frame_size == 0) return 0;
775 return bytes_per_second / frame_size;
776 }
777
779 uint32_t startTime() { return start_time; }
780
781 void setAudioInfo(AudioInfo info) override {
782 AudioStream::info = info;
783 setFrameSize(info.bits_per_sample / 8 * info.channels);
784 }
785
786 bool begin() override {
787 total_bytes_since_begin = 0;
788 ms_at_begin = millis();
789 return AudioStream::begin();
790 }
791
792 bool begin(AudioInfo info) {
793 setAudioInfo(info);
794 return begin();
795 }
796
798 void setFrameSize(int size) { frame_size = size; }
799
801 void setReportBytes(bool flag) { report_bytes = flag; }
802
803 void setName(const char *name) { this->name = name; }
804
806 uint32_t timeSinceBegin() { return millis() - ms_at_begin; }
807
809 uint32_t bytesSinceBegin() { return total_bytes_since_begin; }
810
812 uint32_t estimatedTotalTimeFor(uint32_t totalBytes) {
813 if (bytesSinceBegin() == 0) return 0;
814 return static_cast<float>(timeSinceBegin()) / bytesSinceBegin() *
815 totalBytes;
816 }
817
819 uint32_t estimatedOpenTimeFor(uint32_t totalBytes) {
820 if (bytesSinceBegin() == 0) return 0;
821 return estimatedTotalTimeFor(totalBytes) - timeSinceBegin();
822 }
823
826 bool setProcessedBytes(uint32_t pos) {
827 bool is_regular_update = true;
828 if (pos < total_bytes_since_begin) {
829 begin();
830 is_regular_update = false;
831 }
832 total_bytes_since_begin = pos;
833 return is_regular_update;
834 }
835
836 protected:
837 int max_count = 0;
838 int count = 0;
839 Stream *p_stream = nullptr;
840 Print *p_print = nullptr;
841 uint32_t start_time;
842 int total_bytes = 0;
843 int bytes_per_second = 0;
844 int frame_size = 0;
845 NullStream null;
846 Print *p_logout = nullptr;
847 bool report_bytes = false;
848 const char *name = "";
849 uint32_t ms_at_begin = 0;
850 uint32_t total_bytes_since_begin = 0;
851
852 size_t measure(size_t len) {
853 count--;
854 total_bytes += len;
855
856 if (count <= 0) {
857 uint32_t end_time = millis();
858 int time_diff = end_time - start_time; // in ms
859 if (time_diff > 0) {
860 bytes_per_second = total_bytes / time_diff * 1000;
861 printResult();
862 count = max_count;
863 total_bytes = 0;
864 start_time = end_time;
865 }
866 }
867 return len;
868 }
869
870 void printResult() {
871 char msg[70];
872 if (report_bytes || frame_size == 0) {
873 snprintf(msg, 70, "%s ==> Bytes per second: %d", name, bytes_per_second);
874 } else {
875 snprintf(msg, 70, "%s ==> Samples per second: %d", name,
876 bytes_per_second / frame_size);
877 }
878 if (p_logout != nullptr) {
879 p_logout->println(msg);
880 } else {
881 LOGI("%s", msg);
882 }
883 }
884};
885
893 public:
894 size_t total_size = 0;
895};
904 public:
905 ProgressStream() = default;
906
907 ProgressStream(Print &print) { setPrint(print); }
908
909 ProgressStream(Stream &stream) { setStream(stream); }
910
911 ProgressStream(AudioStream &stream) {
912 setStream(stream);
913 p_info_from = &stream;
914 }
915
916 ProgressStreamInfo &defaultConfig() { return progress_info; }
917
918 void setAudioInfo(AudioInfo info) override {
920 progress_info.copyFrom(info);
921 }
922
923 void setStream(Stream &stream) override {
924 p_stream = &stream;
925 p_print = &stream;
926 }
927
928 void setStream(Print &print) { p_print = &print; }
929
930 void setPrint(Print &print) { p_print = &print; }
931
932 bool begin() override {
933 if (p_info_from != nullptr) {
934 setAudioInfo(p_info_from->audioInfo());
935 }
936 return AudioStream::begin();
937 }
938
941 bool begin(size_t len) {
942 setSize(len);
943 return begin();
944 }
945
946 bool begin(ProgressStreamInfo info) {
947 progress_info = info;
948 setAudioInfo(info);
949 return begin();
950 }
951
953 void setSize(size_t len) {
954 total_processed = 0;
955 progress_info.total_size = len;
956 }
957
959 size_t size() { return progress_info.total_size; }
960
962 size_t processedBytes() { return total_processed; }
963
965 size_t processedSecs() { return total_processed / byteRate(); }
966
968 size_t totalBytes() { return progress_info.total_size; }
969
971 size_t totalSecs() { return totalBytes() / byteRate(); }
972
974 float percentage() {
975 if (progress_info.total_size == 0) return 0;
976 return 100.0 * total_processed / progress_info.total_size;
977 }
978
980 size_t readBytes(uint8_t *data, size_t len) override {
981 if (p_stream == nullptr) return 0;
982 return measure(p_stream->readBytes(data, len));
983 }
984
985 int available() override {
986 if (p_stream == nullptr) return 0;
987 return p_stream->available();
988 }
989
991 virtual size_t write(const uint8_t *data, size_t len) override {
992 if (p_print == nullptr) return 0;
993 return measure(p_print->write(data, len));
994 }
995
997 virtual int availableForWrite() override {
998 if (p_print == nullptr) return 0;
999 return p_print->availableForWrite();
1000 }
1001
1002 protected:
1003 ProgressStreamInfo progress_info;
1004 Stream *p_stream = nullptr;
1005 Print *p_print = nullptr;
1006 AudioInfoSupport *p_info_from = nullptr;
1007 size_t total_processed = 0;
1008
1009 size_t measure(size_t len) {
1010 total_processed += len;
1011 return len;
1012 }
1013
1014 size_t byteRate() {
1015 AudioInfo info = audioInfo();
1016 int byte_rate = info.sample_rate * info.bits_per_sample * info.channels / 8;
1017 if (byte_rate == 0) {
1018 LOGE("Audio Info not defined");
1019 return 0;
1020 }
1021 return byte_rate;
1022 }
1023};
1024
1030struct ThrottleConfig : public AudioInfo {
1031 ThrottleConfig() {
1032 sample_rate = 44100;
1033 bits_per_sample = 16;
1034 channels = 2;
1035 }
1036 int correction_us = 0;
1037};
1038
1046 public:
1047 Throttle() = default;
1048 Throttle(Print &out) { setOutput(out); }
1049 Throttle(Stream &io) { setStream(io); }
1050
1052 void setStream(Stream &io) override {
1053 p_out = &io;
1054 p_in = &io;
1055 };
1056
1058 void setOutput(Print &out) override { p_out = &out; }
1059
1060 ThrottleConfig defaultConfig() {
1062 return c;
1063 }
1064
1065 bool begin(ThrottleConfig cfg) {
1066 LOGI("begin sample_rate: %d, channels: %d, bits: %d", (int)info.sample_rate,
1067 (int)info.channels, (int)info.bits_per_sample);
1068 this->info = cfg;
1069 this->cfg = cfg;
1070 return begin();
1071 }
1072
1073 bool begin(AudioInfo info) {
1074 LOGI("begin sample_rate: %d, channels: %d, bits: %d", (int)info.sample_rate,
1075 (int)info.channels, (int)info.bits_per_sample);
1076 this->info = info;
1077 this->cfg.copyFrom(info);
1078 return begin();
1079 }
1080
1081 bool begin() override {
1082 frame_size = cfg.bits_per_sample / 8 * cfg.channels;
1083 startDelay();
1084 return true;
1085 }
1086
1087 // (re)starts the timing
1088 void startDelay() {
1089 start_time = micros();
1090 sum_frames = 0;
1091 }
1092
1093 int availableForWrite() override {
1094 if (p_out) {
1095 return p_out->availableForWrite();
1096 }
1097 return DEFAULT_BUFFER_SIZE;
1098 }
1099
1100 size_t write(const uint8_t *data, size_t len) override {
1101 size_t result = p_out->write(data, len);
1102 delayBytes(len);
1103 return result;
1104 }
1105
1106 int available() override {
1107 if (p_in == nullptr) return 0;
1108 return p_in->available();
1109 }
1110
1111 size_t readBytes(uint8_t *data, size_t len) override {
1112 if (p_in == nullptr) {
1113 delayBytes(len);
1114 return 0;
1115 }
1116 size_t result = p_in->readBytes(data, len);
1117 delayBytes(len);
1118 return result;
1119 }
1120
1121 // delay
1122 void delayBytes(size_t bytes) { delayFrames(bytes / frame_size); }
1123
1124 // delay
1125 void delayFrames(size_t frames) {
1126 sum_frames += frames;
1127 uint64_t durationUsEff = micros() - start_time;
1128 uint64_t durationUsToBe = getDelayUs(sum_frames);
1129 int64_t waitUs = durationUsToBe - durationUsEff + cfg.correction_us;
1130 LOGD("wait us: %ld", static_cast<long>(waitUs));
1131 if (waitUs > 0) {
1132 int64_t waitMs = waitUs / 1000;
1133 if (waitMs > 0) delay(waitMs);
1134 delayMicroseconds(waitUs - (waitMs * 1000));
1135 } else {
1136 LOGD("negative delay!")
1137 }
1138 }
1139
1140 inline int64_t getDelayUs(uint64_t frames) {
1141 return (frames * 1000000) / cfg.sample_rate;
1142 }
1143
1144 inline int64_t getDelayMs(uint64_t frames) {
1145 return getDelayUs(frames) / 1000;
1146 }
1147
1148 inline int64_t getDelaySec(uint64_t frames) {
1149 return getDelayUs(frames) / 1000000l;
1150 }
1151
1152 protected:
1153 uint32_t start_time = 0;
1154 uint32_t sum_frames = 0;
1155 ThrottleConfig cfg;
1156 int frame_size = 0;
1157 Print *p_out = nullptr;
1158 Stream *p_in = nullptr;
1159};
1160
1170template <typename T>
1171class InputMixer : public AudioStream {
1172 public:
1173 InputMixer() = default;
1174
1176 int add(Stream &in, int weight = 100) {
1177 streams.push_back(&in);
1178 weights.push_back(weight);
1179 total_weights += weight;
1180 return streams.indexOf(&in);
1181 }
1182
1184 bool set(int index, Stream &in) {
1185 if (index < size()) {
1186 streams[index] = &in;
1187 return true;
1188 } else {
1189 LOGE("Invalid index %d - max is %d", index, size() - 1);
1190 return false;
1191 }
1192 }
1193
1194 virtual bool begin(AudioInfo info) {
1195 setAudioInfo(info);
1196 frame_size = info.bits_per_sample / 8 * info.channels;
1197 LOGI("frame_size: %d", frame_size);
1198 return frame_size > 0;
1199 }
1200
1204 void setWeight(int index, int weight) {
1205 if (index < streams.size()) {
1206 weights[index] = weight;
1208 } else {
1209 LOGE("Invalid index %d - max is %d", index, size() - 1);
1210 }
1211 }
1212
1214 void end() override {
1215 streams.clear();
1216 weights.clear();
1217 result_vect.clear();
1218 current_vect.clear();
1219 total_weights = 0.0;
1220 }
1221
1223 int size() { return streams.size(); }
1224
1226 size_t readBytes(uint8_t *data, size_t len) override {
1227 if (total_weights == 0 || frame_size == 0 || len == 0) {
1228 LOGW("readBytes: %d", (int)len);
1229 return 0;
1230 }
1231
1232 if (limit_available_data) {
1233 len = min((int)len, availableBytes());
1234 }
1235
1236 int result_len = 0;
1237
1238 if (len > 0) {
1239 // result_len must be full frames
1240 result_len = len * frame_size / frame_size;
1241 // replace sample based with vector based implementation
1242 // readBytesSamples((T*)data, result_len));
1243 result_len = readBytesVector((T *)data, result_len);
1244 }
1245 return result_len;
1246 }
1247
1250 void setLimitToAvailableData(bool flag) { limit_available_data = flag; }
1251
1254 void setRetryCount(int retry) { retry_count = retry; }
1255
1257 bool remove(int idx){
1258 if (idx < 0 || idx >= size()) {
1259 return false;
1260 }
1261 streams.erase(idx);
1262 weights.erase(idx);
1264 return true;
1265 }
1266
1268 bool remove() {
1269 bool rc = false;
1270 int idx = nextEmptyIndex();
1271 while (idx >= 0) {
1272 rc = true;
1273 streams.erase(idx);
1274 weights.erase(idx);
1275 idx = nextEmptyIndex();
1276 }
1278 return rc;
1279 }
1280
1282 int indexOf(Stream &stream) { return streams.indexOf(&stream); }
1283
1285 Stream *operator[](int idx) {
1286 if (idx < 0 || idx >= size()) return nullptr;
1287 return streams[idx];
1288 }
1289
1292 for (int i = 0; i < streams.size(); i++) {
1293 if (streams[i]->available() == 0) {
1294 return i;
1295 }
1296 }
1297 return -1;
1298 }
1299
1300 protected:
1301 Vector<Stream *> streams{0};
1302 Vector<int> weights{0};
1303 int total_weights = 0;
1304 int frame_size = 4;
1305 bool limit_available_data = false;
1306 int retry_count = 5;
1307 Vector<int> result_vect;
1308 Vector<T> current_vect;
1309
1312 int total = 0;
1313 for (int j = 0; j < weights.size(); j++) {
1314 total += weights[j];
1315 }
1316 total_weights = total;
1317 }
1318
1320 int readBytesVector(T *p_data, int byteCount) {
1321 int samples = byteCount / sizeof(T);
1322 result_vect.resize(samples);
1323 current_vect.resize(samples);
1324 int stream_count = size();
1325 resultClear();
1326 int samples_eff_max = 0;
1327 for (int j = 0; j < stream_count; j++) {
1328 if (weights[j] > 0) {
1329 int samples_eff =
1330 readSamples(streams[j], current_vect.data(), samples, retry_count);
1331 if (samples_eff > samples_eff_max) samples_eff_max = samples_eff;
1332 // if all weights are 0.0 we stop to output
1333 float factor = total_weights == 0.0f
1334 ? 0.0f
1335 : static_cast<float>(weights[j]) / total_weights;
1336 resultAdd(factor);
1337 }
1338 }
1339 // copy result
1340 for (int j = 0; j < samples; j++) {
1341 p_data[j] = result_vect[j];
1342 }
1343 return samples_eff_max * sizeof(T);
1344 }
1345
1348 int result = DEFAULT_BUFFER_SIZE;
1349 for (int j = 0; j < size(); j++) {
1350 result = min(result, streams[j]->available());
1351 }
1352 return result;
1353 }
1354
1355 void resultAdd(float fact) {
1356 for (int j = 0; j < current_vect.size(); j++) {
1357 current_vect[j] *= fact;
1358 result_vect[j] += current_vect[j];
1359 }
1360 }
1361
1362 void resultClear() {
1363 memset(result_vect.data(), 0, sizeof(int) * result_vect.size());
1364 }
1365};
1366
1376template <typename T>
1377class InputMerge : public AudioStream {
1378 public:
1380 InputMerge() = default;
1381
1385 InputMerge(Stream &left, Stream &right) {
1386 add(left, 1);
1387 add(right, 1);
1388 };
1389
1393 info.channels = total_channel_count;
1394 return info;
1395 }
1396
1397 virtual bool begin(AudioInfo info) {
1398 setAudioInfo(info);
1399 return begin();
1400 }
1401
1402 virtual bool begin() override {
1403 // make sure that we use the correct channel count
1404 info.channels = channelCount();
1405 return AudioStream::begin();
1406 }
1407
1409 size_t readBytes(uint8_t *data, size_t len) override {
1410 LOGD("readBytes: %d", (int)len);
1411 T *p_data = (T *)data;
1412 int result_len = MIN(available(), len);
1413 int frames = result_len / (sizeof(T) * total_channel_count);
1414 int result_idx = 0;
1415 for (int j = 0; j < frames; j++) {
1416 for (int i = 0; i < records.size(); i++) {
1417 for (int ch = 0; ch < records[i].channels; ch++) {
1418 p_data[result_idx++] =
1419 records[i].weight * readSample<T>(records[i].stream);
1420 }
1421 }
1422 }
1423 return result_idx * sizeof(T);
1424 }
1425
1427 void add(Stream &in, int channelCount, float weight = 1.0) {
1428 MergeRecord rec(&in, channelCount, weight);
1429 records.push_back(rec);
1430 total_channel_count += channelCount;
1431 }
1432
1435 void setWeight(int channel, float weight) {
1436 if (channel < channelCount()) {
1437 records[channel].weight = weight;
1438 } else {
1439 LOGE("Invalid channel %d - max is %d", channel, channelCount() - 1);
1440 }
1441 }
1442
1444 void end() override { records.clear(); }
1445
1447 int channelCount() { return total_channel_count; }
1448
1450 int available() override {
1451 int result = records[0].stream->available();
1452 for (int j = 1; j < channelCount(); j++) {
1453 int tmp = records[j].stream->available();
1454 if (tmp < result) {
1455 result = tmp;
1456 }
1457 }
1458 return result;
1459 }
1460
1461 protected:
1463 Stream *stream = nullptr;
1464 int channels = 0;
1465 float weight = 1.0;
1466 MergeRecord() = default;
1467 MergeRecord(Stream *str, int ch, float w) {
1468 stream = str;
1469 channels = ch;
1470 weight = w;
1471 }
1472 };
1473 Vector<MergeRecord> records;
1474 int total_channel_count = 0;
1475};
1476
1487 public:
1488 CallbackStream() = default;
1489
1492 CallbackStream(Stream &io, size_t (*cb_update)(uint8_t *data, size_t len)) {
1493 p_stream = &io;
1494 p_out = &io;
1495 setUpdateCallback(cb_update);
1496 }
1497
1499 CallbackStream(Print &out, size_t (*cb_update)(uint8_t *data, size_t len)) {
1500 p_out = &out;
1501 setUpdateCallback(cb_update);
1502 }
1503
1504 CallbackStream(size_t (*cb_read)(uint8_t *data, size_t len),
1505 size_t (*cb_write)(const uint8_t *data, size_t len)) {
1506 setWriteCallback(cb_write);
1507 setReadCallback(cb_read);
1508 }
1509
1510 void setWriteCallback(size_t (*cb_write)(const uint8_t *data, size_t len)) {
1511 this->cb_write = cb_write;
1512 }
1513
1514 void setReadCallback(size_t (*cb_read)(uint8_t *data, size_t len)) {
1515 this->cb_read = cb_read;
1516 }
1517
1518 void setUpdateCallback(size_t (*cb_update)(uint8_t *data, size_t len)) {
1519 this->cb_update = cb_update;
1520 }
1521
1522 // callback result negative -> no change; callbeack result >=0 provides the
1523 // result
1524 void setAvailableCallback(int (*cb)()) { this->cb_available = cb; }
1525
1527 void setAudioInfoCallback(void (*cb)(AudioInfo info)) {
1528 this->cb_audio_info = cb;
1529 }
1530
1532 void setAudioInfo(AudioInfo info) override {
1534 if (cb_audio_info != nullptr) {
1535 cb_audio_info(info);
1536 }
1537 }
1538
1539 virtual bool begin(AudioInfo info) {
1540 setAudioInfo(info);
1541 return begin();
1542 }
1543 virtual bool begin() override {
1544 active = true;
1545 return true;
1546 }
1547
1548 void end() override { active = false; }
1549
1550 int available() override {
1551 int result = AudioStream::available();
1552 // determine value from opional variable
1553 if (available_bytes >= 0) return available_bytes;
1554 // check if there is a callback
1555 if (cb_available == nullptr) return result;
1556 // determine value from callback
1557 int tmp_available = cb_available();
1558 if (tmp_available < 0) return result;
1559
1560 return tmp_available;
1561 }
1562
1563 size_t readBytes(uint8_t *data, size_t len) override {
1564 if (!active) return 0;
1565 // provide data from callback
1566 if (cb_read) {
1567 return cb_read(data, len);
1568 }
1569 // provide data from source
1570 size_t result = 0;
1571 if (p_stream) {
1572 result = p_stream->readBytes(data, len);
1573 }
1574 if (cb_update) {
1575 result = cb_update(data, result);
1576 }
1577 return result;
1578 }
1579
1580 size_t write(const uint8_t *data, size_t len) override {
1581 if (!active) return 0;
1582 // write to callback
1583 if (cb_write) {
1584 return cb_write(data, len);
1585 }
1586 // write to output
1587 if (p_out) {
1588 size_t result = len;
1589 if (cb_update) {
1590 result = cb_update((uint8_t *)data, len);
1591 }
1592 return p_out->write(data, result);
1593 }
1594 // no processing possible
1595 return 0;
1596 }
1597
1599 void setStream(Stream &in) override {
1600 p_stream = &in;
1601 p_out = &in;
1602 }
1603
1605 void setOutput(Print &out) override { p_out = &out; }
1606
1608 void setOutput(Stream &in) {
1609 p_stream = &in;
1610 p_out = &in;
1611 }
1612
1614 void setStream(Print &out) { p_out = &out; }
1615
1617 void setAvailable(int val) { available_bytes = val; }
1618
1619 protected:
1620 bool active = true;
1621 size_t (*cb_write)(const uint8_t *data, size_t len) = nullptr;
1622 size_t (*cb_read)(uint8_t *data, size_t len) = nullptr;
1623 size_t (*cb_update)(uint8_t *data, size_t len) = nullptr;
1624 void (*cb_audio_info)(AudioInfo info) = nullptr;
1625 int (*cb_available)() = nullptr;
1626 Stream *p_stream = nullptr;
1627 Print *p_out = nullptr;
1628 int available_bytes = -1;
1629};
1630
1638template <typename T, class TF>
1640 public:
1641 FilteredStream() = default;
1642 FilteredStream(Stream &stream) : ModifyingStream() { setStream(stream); }
1643 FilteredStream(Stream &stream, int channels) : ModifyingStream() {
1644 this->channels = channels;
1645 setStream(stream);
1646 p_converter = new ConverterNChannels<T, TF>(channels);
1647 }
1648 FilteredStream(Print &stream) : ModifyingStream() { setOutput(stream); }
1649 FilteredStream(Print &stream, int channels) : ModifyingStream() {
1650 this->channels = channels;
1651 setOutput(stream);
1652 p_converter = new ConverterNChannels<T, TF>(channels);
1653 }
1654
1655 virtual ~FilteredStream() { end(); }
1656
1657 void setStream(Stream &stream) override {
1658 p_stream = &stream;
1659 p_print = &stream;
1660 }
1661
1662 void setOutput(Print &stream) override { p_print = &stream; }
1663
1664 bool begin(AudioInfo info) {
1665 setAudioInfo(info);
1666 this->channels = info.channels;
1667 if (p_converter != nullptr && p_converter->getChannels() != channels) {
1668 LOGE("Inconsistent number of channels");
1669 return false;
1670 }
1671 return begin();
1672 }
1673
1674 bool begin() override {
1675 if (channels == 0) {
1676 LOGE("channels must not be 0");
1677 return false;
1678 }
1679 if (p_converter == nullptr) {
1680 p_converter = new ConverterNChannels<T, TF>(channels);
1681 }
1682 return AudioStream::begin();
1683 }
1684
1685 void end() override {
1686 ModifyingStream::end();
1687 if (p_converter != nullptr) {
1688 delete p_converter;
1689 p_converter = nullptr;
1690 }
1691 }
1692
1693 virtual size_t write(const uint8_t *data, size_t len) override {
1694 if (p_converter == nullptr) return 0;
1695 size_t result = p_converter->convert((uint8_t *)data, len);
1696 return p_print->write(data, result);
1697 }
1698
1699 size_t readBytes(uint8_t *data, size_t len) override {
1700 if (p_converter == nullptr) return 0;
1701 if (p_stream == nullptr) return 0;
1702 size_t result = p_stream->readBytes(data, len);
1703 result = p_converter->convert(data, result);
1704 return result;
1705 }
1706
1707 virtual int available() override {
1708 if (p_stream == nullptr) return 0;
1709 return p_stream->available();
1710 }
1711
1712 virtual int availableForWrite() override {
1713 return p_print->availableForWrite();
1714 }
1715
1719 void setFilter(int channel, Filter<TF> *filter) {
1720 if (p_converter != nullptr) {
1721 p_converter->setFilter(channel, filter);
1722 } else {
1723 LOGE("p_converter is null");
1724 }
1725 }
1726
1730 void setFilter(int channel, Filter<TF> &filter) {
1731 setFilter(channel, &filter);
1732 }
1733
1734 protected:
1735 int channels = 0;
1736 Stream *p_stream = nullptr;
1737 Print *p_print = nullptr;
1738 ConverterNChannels<T, TF> *p_converter = nullptr;
1739};
1740
1750 public:
1751 VolumeMeter() = default;
1754 setStream(as);
1755 }
1758 setOutput(ao);
1759 }
1760 VolumeMeter(Print &print) { setOutput(print); }
1761 VolumeMeter(Stream &stream) { setStream(stream); }
1762
1763 bool begin(AudioInfo info) {
1764 setAudioInfo(info);
1765 return begin();
1766 }
1767
1768 bool begin() override {
1770 return true;
1771 }
1772
1773 void setAudioInfo(AudioInfo info) override {
1774 int channels = info.channels;
1775 LOGI("VolumeMeter::setAudioInfo: channels %d", channels);
1777 if (channels > 0) {
1778 volumes.resize(channels);
1779 volumes_tmp.resize(channels);
1780 sum.resize(channels);
1781 sum_tmp.resize(channels);
1782 }
1783 }
1784
1785 size_t write(const uint8_t *data, size_t len) override {
1786 updateVolumes(data, len);
1787 size_t result = len;
1788 if (p_out != nullptr) {
1789 result = p_out->write(data, len);
1790 }
1791 return result;
1792 }
1793
1794 size_t readBytes(uint8_t *data, size_t len) override {
1795 if (p_stream == nullptr) return 0;
1796 size_t result = p_stream->readBytes(data, len);
1797 updateVolumes((const uint8_t *)data, len);
1798 return result;
1799 }
1800
1803 float volume() { return f_volume; }
1804
1807 float volume(int channel) {
1808 if (volumes.size() == 0) {
1809 LOGE("begin not called!");
1810 return 0.0f;
1811 }
1812 if (channel >= volumes.size()) {
1813 LOGE("invalid channel %d", channel);
1814 return 0.0f;
1815 }
1816 return volumes[channel];
1817 }
1818
1820 float volumeRatio() {
1822 }
1823
1825 float volumeRatio(int channel) {
1826 return volume(channel) / NumberConverter::maxValue(info.bits_per_sample);
1827 }
1828
1830 float volumeDB() {
1831 // prevent infinite value
1832 if (volumeRatio() == 0) return -1000;
1833 return 20.0f * log10(volumeRatio());
1834 }
1835
1837 float volumeDB(int channel) {
1838 // prevent infinite value
1839 if (volumeRatio(channel) == 0) return -1000;
1840 return 20.0f * log10(volumeRatio(channel));
1841 }
1842
1844 float volumePercent() { return 100.0f * volumeRatio(); }
1845
1847 float volumePercent(int channel) { return 100.0f * volumeRatio(channel); }
1848
1850 float volumeAvg() {
1851 float total = 0;
1852 size_t count = 0;
1853 for (int j = 0; j < info.channels; j++) {
1854 total += sum[j];
1855 count += sample_count_per_channel;
1856 }
1857 return total / count;
1858 }
1859
1861 float volumeAvg(int channel) {
1862 return sum[channel] / sample_count_per_channel;
1863 }
1864
1866 void clear() {
1867 f_volume_tmp = 0;
1868 for (int j = 0; j < info.channels; j++) {
1869 volumes_tmp[j] = 0;
1870 sum_tmp[j] = 0;
1871 }
1872 }
1873
1874 void setOutput(Print &out) override { p_out = &out; }
1875 void setStream(Stream &io) override {
1876 p_out = &io;
1877 p_stream = &io;
1878 }
1879
1880 protected:
1881 float f_volume_tmp = 0;
1882 float f_volume = 0;
1883 Vector<float> volumes{0};
1884 Vector<float> volumes_tmp{0};
1885 Vector<float> sum{0};
1886 Vector<float> sum_tmp{0};
1887 Print *p_out = nullptr;
1888 Stream *p_stream = nullptr;
1889 size_t sample_count_per_channel = 0;
1890
1891 void updateVolumes(const uint8_t *data, size_t len) {
1892 if (data == nullptr || len == 0) return;
1893 clear();
1894 switch (info.bits_per_sample) {
1895 case 8:
1896 updateVolumesT<int8_t>(data, len);
1897 break;
1898 case 16:
1899 updateVolumesT<int16_t>(data, len);
1900 break;
1901 case 24:
1902 updateVolumesT<int24_t>(data, len);
1903 break;
1904 case 32:
1905 updateVolumesT<int32_t>(data, len);
1906 break;
1907 default:
1908 LOGE("Unsupported bits_per_sample: %d", info.bits_per_sample);
1909 break;
1910 }
1911 }
1912
1913 template <typename T>
1914 void updateVolumesT(const uint8_t *buffer, size_t size) {
1915 T *bufferT = (T *)buffer;
1916 int samplesCount = size / sizeof(T);
1917 sample_count_per_channel = samplesCount / info.channels;
1918 for (int j = 0; j < samplesCount; j++) {
1919 float tmp = abs(static_cast<float>(bufferT[j]));
1920 updateVolume(tmp, j);
1921 }
1922 commit();
1923 }
1924
1925 void updateVolume(float tmp, int j) {
1926 if (tmp > f_volume_tmp) {
1927 f_volume_tmp = tmp;
1928 }
1929 if (volumes_tmp.size() > 0 && info.channels > 0) {
1930 int ch = j % info.channels;
1931 if (tmp > volumes_tmp[ch]) {
1932 volumes_tmp[ch] = tmp;
1933 sum_tmp[ch] = tmp;
1934 }
1935 }
1936 }
1937
1938 void commit() {
1939 f_volume = f_volume_tmp;
1940 for (int j = 0; j < info.channels; j++) {
1941 volumes[j] = volumes_tmp[j];
1942 sum[j] = sum_tmp[j];
1943 }
1944 }
1945};
1946
1947// legacy names
1948using VolumePrint = VolumeMeter;
1949using VolumeOutput = VolumeMeter;
1950
1951#ifdef USE_TIMER
1958 RxTxMode rx_tx_mode = RX_MODE;
1959 uint16_t buffer_size = DEFAULT_BUFFER_SIZE;
1960 bool use_timer = true;
1961 int timer_id = -1;
1962 TimerFunction timer_function = DirectTimerCallback;
1963 bool adapt_sample_rate = false;
1964 uint16_t (*callback)(uint8_t *data, uint16_t len) = nullptr;
1965};
1966
1967// forward declaration: relevant only if use_timer == true
1968static void timerCallback(void *obj);
1979 friend void timerCallback(void *obj);
1980
1981 public:
1982 TimerCallbackAudioStream() : BufferedStream(80) { TRACED(); }
1983
1985 TRACED();
1986 if (timer != nullptr) delete timer;
1987 if (buffer != nullptr) delete buffer;
1988 if (frame != nullptr) delete[] frame;
1989 }
1990
1996
1998 virtual void setAudioInfo(AudioInfo info) {
1999 TRACED();
2000 if (cfg.sample_rate != info.sample_rate || cfg.channels != info.channels ||
2001 cfg.bits_per_sample != info.bits_per_sample) {
2002 bool do_restart = active;
2003 if (do_restart) end();
2004 cfg.sample_rate = info.sample_rate;
2005 cfg.channels = info.channels;
2006 cfg.bits_per_sample = info.bits_per_sample;
2007 if (do_restart) begin(cfg);
2008 }
2009 }
2010
2013 AudioInfo audioInfo() { return cfg; }
2014
2015 void begin(TimerCallbackAudioStreamInfo config) {
2016 LOGD("%s: %s", LOG_METHOD,
2017 config.rx_tx_mode == RX_MODE ? "RX_MODE" : "TX_MODE");
2018 this->cfg = config;
2019 this->frameCallback = config.callback;
2020 if (cfg.use_timer) {
2021 frameSize = cfg.bits_per_sample * cfg.channels / 8;
2022 frame = new uint8_t[frameSize];
2023 buffer = new RingBuffer<uint8_t>(cfg.buffer_size);
2024 timer = new TimerAlarmRepeating();
2025 timer->setTimerFunction(cfg.timer_function);
2026 if (cfg.timer_id >= 0) {
2027 timer->setTimer(cfg.timer_id);
2028 }
2029 time = AudioTime::toTimeUs(cfg.sample_rate);
2030 LOGI("sample_rate: %u -> time: %u milliseconds",
2031 (unsigned int)cfg.sample_rate, (unsigned int)time);
2032 timer->setCallbackParameter(this);
2033 timer->begin(timerCallback, time, TimeUnit::US);
2034 }
2035
2036 notifyAudioChange(cfg);
2037 active = true;
2038 }
2039
2041 bool begin() {
2042 TRACED();
2043 if (this->frameCallback != nullptr) {
2044 if (cfg.use_timer) {
2045 timer->begin(timerCallback, time, TimeUnit::US);
2046 }
2047 active = true;
2048 }
2049 return active;
2050 }
2051
2053 void end() {
2054 TRACED();
2055 if (cfg.use_timer) {
2056 timer->end();
2057 }
2058 active = false;
2059 }
2060
2062 uint16_t currentSampleRate() { return currentRateValue; }
2063
2064 protected:
2066 bool active = false;
2067 uint16_t (*frameCallback)(uint8_t *data, uint16_t len);
2068 // below only relevant with timer
2069 TimerAlarmRepeating *timer = nullptr;
2070 RingBuffer<uint8_t> *buffer = nullptr;
2071 uint8_t *frame = nullptr;
2072 uint16_t frameSize = 0;
2073 uint32_t time = 0;
2074 unsigned long lastTimestamp = 0u;
2075 uint32_t currentRateValue = 0;
2076 uint32_t printCount = 0;
2077
2078 // used for audio sink
2079 virtual size_t writeExt(const uint8_t *data, size_t len) override {
2080 if (!active) return 0;
2081 TRACED();
2082 size_t result = 0;
2083 if (!cfg.use_timer) {
2084 result = frameCallback((uint8_t *)data, len);
2085 } else {
2086 result = buffer->writeArray((uint8_t *)data, len);
2087 }
2088 if (++printCount % 10000 == 0) printSampleRate();
2089 return result;
2090 }
2091
2092 // used for audio source
2093 virtual size_t readExt(uint8_t *data, size_t len) override {
2094 if (!active) return 0;
2095 TRACED();
2096
2097 size_t result = 0;
2098 if (!cfg.use_timer) {
2099 result = frameCallback(data, len);
2100 } else {
2101 result = buffer->readArray(data, len);
2102 }
2103 if (++printCount % 10000 == 0) printSampleRate();
2104 return result;
2105 }
2106
2108 virtual void measureSampleRate() {
2109 unsigned long ms = millis();
2110 if (lastTimestamp > 0u) {
2111 uint32_t diff = ms - lastTimestamp;
2112 if (diff > 0) {
2113 uint16_t rate = 1 * 1000 / diff;
2114
2115 if (currentRateValue == 0) {
2116 currentRateValue = rate;
2117 } else {
2118 currentRateValue = (currentRateValue + rate) / 2;
2119 }
2120 }
2121 }
2122 lastTimestamp = ms;
2123 }
2124
2126 virtual void printSampleRate() {
2127 LOGI("effective sample rate: %u", (unsigned int)currentRateValue);
2128 if (cfg.adapt_sample_rate &&
2129 abs((int)currentRateValue - (int)cfg.sample_rate) > 200) {
2130 cfg.sample_rate = currentRateValue;
2131 notifyAudioChange(cfg);
2132 }
2133 }
2134};
2135
2136// relevant only if use_timer == true
2137void IRAM_ATTR timerCallback(void *obj) {
2138 TimerCallbackAudioStream *src = (TimerCallbackAudioStream *)obj;
2139 if (src != nullptr) {
2140 // LOGD("%s: %s", LOG_METHOD, src->cfg.rx_tx_mode==RX_MODE ?
2141 // "RX_MODE":"TX_MODE");
2142 if (src->cfg.rx_tx_mode == RX_MODE) {
2143 // input
2144 uint16_t available_bytes = src->frameCallback(src->frame, src->frameSize);
2145 uint16_t buffer_available = src->buffer->availableForWrite();
2146 if (buffer_available < available_bytes) {
2147 // if buffer is full make space
2148 uint16_t to_clear = available_bytes - buffer_available;
2149 uint8_t tmp[to_clear];
2150 src->buffer->readArray(tmp, to_clear);
2151 }
2152 if (src->buffer->writeArray(src->frame, available_bytes) !=
2153 available_bytes) {
2154 assert(false);
2155 }
2156 } else {
2157 // output
2158 if (src->buffer != nullptr && src->frame != nullptr &&
2159 src->frameSize > 0) {
2160 uint16_t available_bytes =
2161 src->buffer->readArray(src->frame, src->frameSize);
2162 if (available_bytes !=
2163 src->frameCallback(src->frame, available_bytes)) {
2164 LOGE("data underflow");
2165 }
2166 }
2167 }
2168 src->measureSampleRate();
2169 }
2170}
2171
2172#endif
2173
2174} // namespace audio_tools
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:151
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:133
virtual AudioInfo audioInfo()=0
provides the actual input AudioInfo
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Abstract Audio Ouptut class.
Definition AudioOutput.h:22
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:122
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:130
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition BaseStream.h:153
To be used to support implementations where the readBytes is not virtual.
Definition AudioStreams.h:23
static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10)
converts sampling rate to delay in microseconds (μs)
Definition AudioTypes.h:240
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:33
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:55
Abstract Base class for Converters A converter is processing the data in the indicated array.
Definition BaseConverter.h:24
The Arduino Stream supports operations on single characters. This is usually not the best way to push...
Definition AudioStreams.h:483
void flush() override
empties the buffer
Definition AudioStreams.h:540
void setOutput(Print &out) override
Defines/Changes the output target.
Definition AudioStreams.h:514
void setMinUnbufferedReadSize(size_t size)
Defines the minimum direct unbuffered read size to the original source (default is 1024)
Definition AudioStreams.h:599
size_t write(uint8_t c) override
writes a byte to the buffer
Definition AudioStreams.h:522
size_t readBytes(uint8_t *data, size_t len) override
Use this method !!
Definition AudioStreams.h:569
int peek() override
peeks a byte - to be avoided
Definition AudioStreams.h:559
void refill()
refills the buffer with data from the source
Definition AudioStreams.h:610
int available() override
Returns the available bytes.
Definition AudioStreams.h:587
size_t write(const uint8_t *data, size_t len) override
Use this method: write an array.
Definition AudioStreams.h:530
size_t peekBytes(uint8_t *data, size_t len)
Provides data w/o consuming.
Definition AudioStreams.h:579
void clear()
Clears all the data in the buffer.
Definition AudioStreams.h:593
int read() override
reads a byte - to be avoided
Definition AudioStreams.h:549
void refill(size_t len)
refill only if not enough data
Definition AudioStreams.h:625
void resize(int size)
Resize the buffer.
Definition AudioStreams.h:596
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition AudioStreams.h:516
CallbackStream: A Stream that allows to register callback methods for accessing and providing data....
Definition AudioStreams.h:1486
void setOutput(Print &out) override
Defines/Changes the output target.
Definition AudioStreams.h:1605
void setOutput(Stream &in)
same as setStream
Definition AudioStreams.h:1608
CallbackStream(Print &out, size_t(*cb_update)(uint8_t *data, size_t len))
Allows to change the audio before sending it to the output.
Definition AudioStreams.h:1499
void setStream(Print &out)
same as set Output
Definition AudioStreams.h:1614
void setAvailable(int val)
optioinally define available bytes for next read
Definition AudioStreams.h:1617
void setAudioInfo(AudioInfo info) override
Updates the audio info and calls the callback.
Definition AudioStreams.h:1532
void setStream(Stream &in) override
Defines/Changes the input & output.
Definition AudioStreams.h:1599
CallbackStream(Stream &io, size_t(*cb_update)(uint8_t *data, size_t len))
Definition AudioStreams.h:1492
void setAudioInfoCallback(void(*cb)(AudioInfo info))
defines the callback to receive the actual audio info
Definition AudioStreams.h:1527
Converter for n Channels which applies the indicated Filter.
Definition BaseConverter.h:1581
void setFilter(int channel, Filter< FT > *filter)
defines the filter for an individual channel - the first channel is 0
Definition BaseConverter.h:1605
Both the data of the read or write operations will be converted with the help of the indicated conver...
Definition AudioStreams.h:647
void setStream(Stream &stream)
Defines/Changes the input & output.
Definition AudioStreams.h:663
void setOutput(Print &out)
Defines/Changes the output target.
Definition AudioStreams.h:669
virtual int available() override
Returns the available bytes in the buffer: to be avoided.
Definition AudioStreams.h:694
Abstract filter interface definition;.
Definition Filter.h:28
Stream to which we can apply Filters for each channel. The filter might change the result size!
Definition AudioStreams.h:1639
void setStream(Stream &stream) override
Defines/Changes the input & output.
Definition AudioStreams.h:1657
void setOutput(Print &stream) override
Defines/Changes the output target.
Definition AudioStreams.h:1662
void setFilter(int channel, Filter< TF > &filter)
Definition AudioStreams.h:1730
void setFilter(int channel, Filter< TF > *filter)
Definition AudioStreams.h:1719
Source for reading generated tones. Please note.
Definition AudioStreams.h:394
void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition AudioStreams.h:409
size_t readBytes(uint8_t *data, size_t len) override
privide the data as byte stream
Definition AudioStreams.h:457
void end() override
stop the processing
Definition AudioStreams.h:443
bool begin() override
start the processing
Definition AudioStreams.h:417
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition AudioStreams.h:449
bool begin(AudioInfo cfg)
start the processing
Definition AudioStreams.h:430
virtual int available() override
This is unbounded so we just return the buffer size.
Definition AudioStreams.h:452
Merges multiple input streams. So if you provide 2 mono channels you get a stereo signal as result wi...
Definition AudioStreams.h:1377
InputMerge()=default
Default constructor.
size_t readBytes(uint8_t *data, size_t len) override
Provides the data from all streams mixed together.
Definition AudioStreams.h:1409
void end() override
Remove all input streams.
Definition AudioStreams.h:1444
int available() override
Provides the min available data from all streams.
Definition AudioStreams.h:1450
void add(Stream &in, int channelCount, float weight=1.0)
Adds a new input stream with 1 channel.
Definition AudioStreams.h:1427
void setWeight(int channel, float weight)
Definition AudioStreams.h:1435
int channelCount()
Number of channels to which are mixed together = number of result channels.
Definition AudioStreams.h:1447
InputMerge(Stream &left, Stream &right)
Constructor for stereo signal from to mono input stream.
Definition AudioStreams.h:1385
AudioInfo audioInfo() override
Provides the audio info with the total channel count.
Definition AudioStreams.h:1391
MixerStream is mixing the input from Multiple Input Streams. All streams must have the same audo form...
Definition AudioStreams.h:1171
bool remove()
Removes all streams which have no data available.
Definition AudioStreams.h:1268
int nextEmptyIndex()
Provides you the index of the next empty stream. -1 when none is found.
Definition AudioStreams.h:1291
int indexOf(Stream &stream)
Provides the actual index of the stream.
Definition AudioStreams.h:1282
bool set(int index, Stream &in)
Replaces a stream at the indicated index.
Definition AudioStreams.h:1184
size_t readBytes(uint8_t *data, size_t len) override
Provides the data from all streams mixed together.
Definition AudioStreams.h:1226
void recalculateWeights()
Recalculate the weights.
Definition AudioStreams.h:1311
int add(Stream &in, int weight=100)
Adds a new input stream and returns it's actual index position.
Definition AudioStreams.h:1176
void end() override
Remove all input streams.
Definition AudioStreams.h:1214
bool remove(int idx)
Removes a stream by index position.
Definition AudioStreams.h:1257
int availableBytes()
Provides the available bytes from the first stream with data.
Definition AudioStreams.h:1347
void setLimitToAvailableData(bool flag)
Definition AudioStreams.h:1250
void setRetryCount(int retry)
Definition AudioStreams.h:1254
int readBytesVector(T *p_data, int byteCount)
mixing using a vector of samples
Definition AudioStreams.h:1320
void setWeight(int index, int weight)
Definition AudioStreams.h:1204
Stream * operator[](int idx)
Provides the stream pointer at the indicated index.
Definition AudioStreams.h:1285
int size()
Number of stremams to which are mixed together.
Definition AudioStreams.h:1223
Class which measures the thruput.
Definition AudioStreams.h:711
virtual size_t write(const uint8_t *data, size_t len) override
Writes raw PCM audio data, which will be the input for the volume control.
Definition AudioStreams.h:759
void setOutput(Print &out) override
Defines/Changes the output target.
Definition AudioStreams.h:748
uint32_t estimatedTotalTimeFor(uint32_t totalBytes)
Provides the estimated runtime in milliseconds for the indicated total.
Definition AudioStreams.h:812
uint32_t timeSinceBegin()
Provides the time in ms since the last call of begin()
Definition AudioStreams.h:806
size_t readBytes(uint8_t *data, size_t len) override
Provides the data from all streams mixed together.
Definition AudioStreams.h:751
int framesPerSecond()
Returns the actual thrughput in frames (samples) per second.
Definition AudioStreams.h:773
uint32_t bytesSinceBegin()
Provides the total processed bytes since the last call of begin()
Definition AudioStreams.h:809
virtual int availableForWrite() override
Provides the nubmer of bytes we can write.
Definition AudioStreams.h:765
void setFrameSize(int size)
Trigger reporting in frames (=samples) per second.
Definition AudioStreams.h:798
void setReportBytes(bool flag)
Report in bytes instead of samples.
Definition AudioStreams.h:801
uint32_t estimatedOpenTimeFor(uint32_t totalBytes)
Provides the estimated time from now to the end in ms.
Definition AudioStreams.h:819
void setLogOutput(Print &out)
Defines the logging output.
Definition AudioStreams.h:739
bool setProcessedBytes(uint32_t pos)
Definition AudioStreams.h:826
uint32_t startTime()
Provides the time when the last measurement was started.
Definition AudioStreams.h:779
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition AudioStreams.h:781
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition AudioStreams.h:742
int bytesPerSecond()
Returns the actual thrughput in bytes per second.
Definition AudioStreams.h:770
A simple Stream implementation which is backed by allocated memory.
Definition AudioStreams.h:83
MemoryStream(const uint8_t *buffer, int buffer_size, bool isActive=true, MemoryType memoryType=FLASH_RAM)
Definition AudioStreams.h:98
virtual void setLoop(bool loop, int rewindPos)
Automatically rewinds to the indicated position when reaching the end.
Definition AudioStreams.h:261
virtual void clear(bool reset=false)
clears the audio data: sets all values to 0
Definition AudioStreams.h:231
virtual uint8_t * data()
Provides access to the data array.
Definition AudioStreams.h:288
virtual void setAvailable(size_t len)
update the write_pos (e.g. when we used data() to update the array)
Definition AudioStreams.h:291
void setValue(const uint8_t *buffer, int buffer_size, MemoryType memoryType=FLASH_RAM)
Update the values (buffer and size)
Definition AudioStreams.h:297
MemoryStream(MemoryStream &&source)
Move Constructor.
Definition AudioStreams.h:110
MemoryStream(MemoryStream &source)
Copy Constructor.
Definition AudioStreams.h:107
virtual void setLoop(bool loop)
Definition AudioStreams.h:250
virtual bool resize(size_t size)
Definition AudioStreams.h:268
MemoryStream(int buffer_size, MemoryType memoryType)
Constructor for alloction in RAM.
Definition AudioStreams.h:88
bool begin() override
resets the read pointer
Definition AudioStreams.h:137
MemoryStream & operator=(MemoryStream &other)
copy assignement operator
Definition AudioStreams.h:122
bool begin(AudioInfo info)
Define some audio info and start the processing.
Definition AudioStreams.h:131
void setRewindCallback(void(*cb)())
Callback which is executed when we rewind (in loop mode) to the beginning.
Definition AudioStreams.h:294
Abstract class: Objects can be put into a pipleline.
Definition AudioStreams.h:68
virtual void setStream(Stream &in)=0
Defines/Changes the input & output.
virtual void setOutput(Print &out)=0
Defines/Changes the output target.
The Arduino Stream which provides silence and simulates a null device when used as audio target or au...
Definition BaseStream.h:292
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition AudioTypes.h:299
Definition NoArduino.h:62
Generic calss to measure the the total bytes which were processed in order to calculate the progress ...
Definition AudioStreams.h:903
bool begin(size_t len)
Definition AudioStreams.h:941
virtual size_t write(const uint8_t *data, size_t len) override
Writes raw PCM audio data, which will be the input for the volume control.
Definition AudioStreams.h:991
size_t size()
Provides the current total size (defined by setSize)
Definition AudioStreams.h:959
void setStream(Stream &stream) override
Defines/Changes the input & output.
Definition AudioStreams.h:923
size_t totalSecs()
Converts the totalBytes() to seconds.
Definition AudioStreams.h:971
size_t readBytes(uint8_t *data, size_t len) override
Provides the data from all streams mixed together.
Definition AudioStreams.h:980
size_t processedBytes()
Provides the number of processed bytes.
Definition AudioStreams.h:962
void setSize(size_t len)
Updates the total size and restarts the percent calculation.
Definition AudioStreams.h:953
virtual int availableForWrite() override
Provides the nubmer of bytes we can write.
Definition AudioStreams.h:997
float percentage()
Provides the processed percentage: If no size has been defined we return 0.
Definition AudioStreams.h:974
size_t processedSecs()
Provides the number of processed seconds.
Definition AudioStreams.h:965
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition AudioStreams.h:918
size_t totalBytes()
Provides the total_size provided in the configuration.
Definition AudioStreams.h:968
Configuration for ProgressStream.
Definition AudioStreams.h:892
Implements a typed Ringbuffer.
Definition Buffers.h:336
An AudioStream backed by a Ringbuffer. We can write to the end and read from the beginning of the str...
Definition AudioStreams.h:338
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
Base class to define the abstract interface for the sound generating classes.
Definition SoundGenerator.h:28
virtual size_t readBytes(uint8_t *data, size_t len)
Provides the data as byte array with the requested number of channels.
Definition SoundGenerator.h:62
virtual bool isActive()
Definition SoundGenerator.h:56
virtual AudioInfo audioInfo()
Provides the AudioInfo.
Definition SoundGenerator.h:87
virtual void end()
ends the processing
Definition SoundGenerator.h:52
virtual AudioInfo defaultConfig()
Provides the default configuration.
Definition SoundGenerator.h:75
Definition NoArduino.h:142
Throttle the sending or receiving of the audio data to limit it to the indicated sample rate.
Definition AudioStreams.h:1045
void setOutput(Print &out) override
Defines/Changes the output target.
Definition AudioStreams.h:1058
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition AudioStreams.h:1052
Common Interface definition for TimerAlarmRepeating.
Definition AudioTimer.h:25
Callback driven Audio Source (rx_tx_mode==RX_MODE) or Audio Sink (rx_tx_mode==TX_MODE)....
Definition AudioStreams.h:1978
TimerCallbackAudioStreamInfo audioInfoExt()
Provides the current audio information.
Definition AudioStreams.h:2012
uint16_t currentSampleRate()
Provides the effective sample rate.
Definition AudioStreams.h:2062
TimerCallbackAudioStreamInfo defaultConfig()
Provides the default configuration.
Definition AudioStreams.h:1992
bool begin()
Restart the processing.
Definition AudioStreams.h:2041
AudioInfo audioInfo()
provides the actual input AudioInfo
Definition AudioStreams.h:2013
virtual void measureSampleRate()
calculates the effective sample rate
Definition AudioStreams.h:2108
virtual void setAudioInfo(AudioInfo info)
updates the audio information
Definition AudioStreams.h:1998
virtual void printSampleRate()
log and update effective sample rate
Definition AudioStreams.h:2126
void end()
Stops the processing.
Definition AudioStreams.h:2053
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
A simple class to determine the volume. You can use it as final output or as output or input in your ...
Definition AudioStreams.h:1749
void setOutput(Print &out) override
Defines/Changes the output target.
Definition AudioStreams.h:1874
float volumeRatio()
Volume Ratio: max amplitude is 1.0.
Definition AudioStreams.h:1820
float volumeAvg(int channel)
Average volume of indicated channel.
Definition AudioStreams.h:1861
float volume()
Definition AudioStreams.h:1803
float volumePercent()
Volume in %: max amplitude is 100.
Definition AudioStreams.h:1844
float volumePercent(int channel)
Volume of indicated channel in %: max amplitude is 100.
Definition AudioStreams.h:1847
float volumeAvg()
Average volume of all channels.
Definition AudioStreams.h:1850
void clear()
Resets the actual volume.
Definition AudioStreams.h:1866
float volumeRatio(int channel)
Volume Ratio of indicated channel: max amplitude is 1.0.
Definition AudioStreams.h:1825
float volumeDB(int channel)
Volume of indicated channel in db: max amplitude is 0.
Definition AudioStreams.h:1837
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition AudioStreams.h:1773
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition AudioStreams.h:1875
float volumeDB()
Volume in db: max amplitude is 0 (range: -1000 to 0)
Definition AudioStreams.h:1830
float volume(int channel)
Definition AudioStreams.h:1807
MemoryType
Memory types.
Definition AudioTypes.h:35
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:28
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
size_t readSamples(Stream *p_stream, T *data, int samples, int retryCount=-1)
guaranteed to return the requested data
Definition AudioTypes.h:466
uint32_t millis()
Returns the milliseconds since the start.
Definition Time.h:12
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
void copyFrom(AudioInfo info)
Same as set.
Definition AudioTypes.h:103
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59
Definition AudioStreams.h:1462
Configure Throttle setting.
Definition AudioStreams.h:1030
TimerCallbackAudioStream Configuration.
Definition AudioStreams.h:1957