12struct AudioSinkAdapter :
public audio::AudioSinkCallback {
16 size_t audio_sink_write(uint8_t *data,
size_t length, TickType_t ticks_to_wait)
override {
17 return this->source->write_output(data,
length, pdTICKS_TO_MS(ticks_to_wait), this->stream_info);
22#if defined(USE_AUDIO_OPUS_SUPPORT)
23static constexpr uint32_t DECODE_TASK_STACK_SIZE = 5 * 1024;
25static constexpr uint32_t DECODE_TASK_STACK_SIZE = 3 * 1024;
28static const char *
const TAG =
"audio_file_media_source";
48 ESP_LOGCONFIG(TAG,
"Audio File Media Source:");
57 ESP_LOGE(TAG,
"Failed to create event group");
64 EventBits_t event_bits = xEventGroupGetBits(this->
event_group_);
76 this->task_stack_in_psram_)) {
77 ESP_LOGE(TAG,
"Failed to create task");
89 ESP_LOGD(TAG,
"Starting");
94 ESP_LOGV(TAG,
"Started");
106 ESP_LOGV(TAG,
"Stopping");
107 xEventGroupClearBits(this->
event_group_, TASK_STOPPING);
116 ESP_LOGD(TAG,
"Stopped");
148 ESP_LOGE(TAG,
"Cannot play '%s': source is busy", uri.c_str());
153 if (!uri.starts_with(
"audio-file://")) {
154 ESP_LOGE(TAG,
"Invalid URI: '%s'", uri.c_str());
159 const char *file_id = uri.c_str() + 13;
162 if (strcmp(named_file.file_id, file_id) == 0) {
170 ESP_LOGE(TAG,
"Unknown file: '%s'", file_id);
203 std::unique_ptr<audio::AudioDecoder> decoder = make_unique<audio::AudioDecoder>(0, 4096);
207 ESP_LOGE(TAG,
"Failed to start decoder: %s", esp_err_to_name(err));
217 AudioSinkAdapter audio_sink;
218 bool has_stream_info =
false;
221 EventBits_t event_bits = xEventGroupGetBits(this_source->
event_group_);
228 decoder->set_pause_output_state(paused);
231 vTaskDelay(pdMS_TO_TICKS(20));
242 ESP_LOGE(TAG,
"Decoder failed");
247 if (!has_stream_info && decoder->get_audio_stream_info().has_value()) {
248 has_stream_info =
true;
252 ESP_LOGD(TAG,
"Bits per sample: %d, Channels: %d, Sample rate: %d",
stream_info.get_bits_per_sample(),
256 ESP_LOGE(TAG,
"Incompatible audio stream. Only 16 bits per sample and 1 or 2 channels are supported");
261 audio_sink.source = this_source;
263 esp_err_t err = decoder->add_sink(&audio_sink);
265 ESP_LOGE(TAG,
"Failed to add sink: %s", esp_err_to_name(err));
278 vTaskSuspend(
nullptr);
void mark_failed()
Mark this component as failed.
void status_momentary_error(const char *name, uint32_t length=5000)
Set error status flag and automatically clear it after a timeout.
void enable_loop()
Enable this component's loop.
bool status_has_error() const
void disable_loop()
Disable this component's loop.
bool create(TaskFunction_t fn, const char *name, uint32_t stack_size, void *param, UBaseType_t priority, bool use_psram)
Allocate stack and create task.
bool is_created() const
Check if the task has been created and not yet destroyed.
void deallocate()
Delete the task (if running) and free the stack buffer.
const StaticVector< NamedAudioFile, AUDIO_FILE_MAX_FILES > & get_named_audio_files()