3#include "AudioTools/AudioCodecs/AudioCodecs.h"
4#include "AudioTools/CoreAudio/AudioBasic/Debouncer.h"
5#include "AudioTools/CoreAudio/AudioLogger.h"
6#include "AudioTools/CoreAudio/AudioMetaData/MetaData.h"
7#include "AudioTools/CoreAudio/AudioStreams.h"
8#include "AudioTools/CoreAudio/AudioTypes.h"
9#include "AudioTools/CoreAudio/BaseConverter.h"
10#include "AudioTools/CoreAudio/Buffers.h"
11#include "AudioTools/CoreAudio/Fade.h"
12#include "AudioTools/CoreAudio/StreamCopy.h"
13#include "AudioTools/CoreAudio/VolumeStream.h"
14#include "AudioTools/Disk/AudioSource.h"
15#include "AudioToolsConfig.h"
67 this->p_source = &source;
68 this->p_decoder = &decoder;
87 this->p_source = &source;
88 this->p_decoder = &decoder;
104 this->p_source = &source;
105 this->p_decoder = &decoder;
123 out_decoding.setDecoder(p_decoder);
126 out_decoding.setDecoder(p_decoder);
128 this->p_final_print = &output;
129 this->p_final_stream =
nullptr;
138 out_decoding.setDecoder(p_decoder);
141 out_decoding.setDecoder(p_decoder);
143 this->p_final_print =
nullptr;
144 this->p_final_stream =
nullptr;
153 out_decoding.setDecoder(p_decoder);
156 out_decoding.setDecoder(p_decoder);
158 this->p_final_print =
nullptr;
159 this->p_final_stream = &output;
170 if (current_volume == -1.0f) {
183 out_decoding.
begin();
185 if (!p_source->
begin()){
186 LOGE(
"Could not start audio source");
189 if (!meta_out.begin()){
190 LOGE(
"Could not start metadata output");
193 if (!volume_out.begin()){
194 LOGE(
"Could not start volume control");
200 if (p_input_stream !=
nullptr) {
204 copier.
begin(out_decoding, *p_input_stream);
209 LOGW(
"-> begin: no data found");
214 LOGW(
"-> begin: no stream selected");
228 if (p_decoder !=
nullptr) {
243 this->p_decoder = &decoder;
244 out_decoding.setDecoder(p_decoder);
249 this->p_final_notify = notify;
251 if (p_decoder !=
nullptr) {
261 LOGI(
"channels: %d", (
int)info.
channels);
267 if (p_final_print !=
nullptr) p_final_print->
setAudioInfo(info);
268 if (p_final_stream !=
nullptr) p_final_stream->
setAudioInfo(info);
269 if (p_final_notify !=
nullptr) p_final_notify->
setAudioInfo(info);
288 LOGW(
"Could not open file: %s", path);
292 LOGI(
"Playing %s", path);
298 LOGI(
"%s has finished playing", path);
316 stream_increment = offset >= 0 ? 1 : -1;
325 stream_increment = 1;
334 stream_increment = 1;
343 stream_increment = -1;
351 out_decoding.
begin();
352 p_input_stream = input;
353 if (p_input_stream !=
nullptr) {
354 LOGD(
"open selected stream");
356 copier.
begin(out_decoding, *p_input_stream);
359 if (on_stream_change_callback !=
nullptr)
360 on_stream_change_callback(p_input_stream, p_reference);
361 return p_input_stream !=
nullptr;
377 fade.setFadeInActive(
true);
379 fade.setFadeOutActive(
true);
391 if (abs(
volume - current_volume) > 0.01f) {
392 LOGI(
"setVolume(%f)",
volume);
397 LOGE(
"setVolume value '%f' out of range (0.0 -1.0)",
volume);
404 float volume()
override {
return current_volume; }
419 size_t step =
copy();
431 if (delay_if_full != 0 && ((p_final_print !=
nullptr &&
432 p_final_print->availableForWrite() == 0) ||
433 (p_final_stream !=
nullptr &&
434 p_final_stream->availableForWrite() == 0))) {
436 delay(delay_if_full);
437 LOGD(
"copy: %d -> 0", (
int)bytes);
442 if (result > 0 || timeout == 0) {
447 moveToNextFileOnTimeout();
450 if (result < bytes && silence_on_inactive) {
456 if (silence_on_inactive) {
460 LOGD(
"copy: %d -> %d", (
int)bytes, (
int)result);
480 if (p_final_print !=
nullptr) {
482 }
else if (p_final_stream !=
nullptr) {
508 if (p_source->setMetadataCallback(callback)) {
510 LOGI(
"Using ICY Metadata");
514 meta_out.setCallback(callback);
515 meta_out.setFilter(sel);
523 on_stream_change_callback = callback;
524 if (p_input_stream!=
nullptr) callback(p_input_stream, p_reference);
529 bool autonext =
true;
530 bool silence_on_inactive =
false;
537 AudioDecoder *p_decoder = &no_decoder;
538 Stream *p_input_stream =
nullptr;
539 AudioOutput *p_final_print =
nullptr;
540 AudioStream *p_final_stream =
nullptr;
541 AudioInfoSupport *p_final_notify =
nullptr;
544 bool meta_active =
false;
545 uint32_t timeout = 0;
546 int stream_increment = 1;
547 float current_volume = -1.0f;
548 int delay_if_full = 100;
549 bool is_auto_fade =
true;
550 void *p_reference =
nullptr;
551 void (*on_stream_change_callback)(Stream *stream_ptr,
552 void *reference) =
nullptr;
555 if (p_final_print !=
nullptr) {
557 }
else if (p_final_stream !=
nullptr) {
562 void moveToNextFileOnTimeout() {
563 if (p_final_stream !=
nullptr && p_final_stream->availableForWrite() == 0)
565 if (p_input_stream ==
nullptr ||
millis() > timeout) {
566 if (is_auto_fade) fade.setFadeInActive(
true);
568 LOGI(
"-> timeout - moving by %d", stream_increment);
570 if (!
next(stream_increment)) {
571 LOGD(
"stream is null");
584 fade.setFadeOutActive(
true);
587 fade.setFadeInActive(
true);
596 LOGD(
"%s, %zu", LOG_METHOD, len);
598 if (p->meta_active) {
599 p->meta_out.
write((
const uint8_t *)data, len);