48static const uint32_t MEDIA_CONTROLS_QUEUE_LENGTH = 20;
50static const UBaseType_t MEDIA_PIPELINE_TASK_PRIORITY = 1;
51static const UBaseType_t ANNOUNCEMENT_PIPELINE_TASK_PRIORITY = 1;
55static constexpr uint32_t UNPAUSE_MEDIA_INTERVAL_ID = 0;
56static constexpr uint32_t NEXT_ANNOUNCEMENT_TIMEOUT_ID = 1;
57static constexpr uint32_t NEXT_MEDIA_TIMEOUT_ID = 2;
58static constexpr uint32_t UNPAUSE_ANNOUNCEMENT_INTERVAL_ID = 3;
61#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
71 VolumeRestoreState volume_restore_state;
72 if (this->
pref_.
load(&volume_restore_state)) {
80#ifdef USE_OTA_STATE_LISTENER
86 ANNOUNCEMENT_PIPELINE_TASK_PRIORITY);
89 ESP_LOGE(TAG,
"Failed to create announcement pipeline");
98 ESP_LOGE(TAG,
"Failed to create media pipeline");
103 ESP_LOGI(TAG,
"Set up speaker media player");
107 switch (pipeline_type) {
120 this->
set_interval(UNPAUSE_MEDIA_INTERVAL_ID, 50, [
this]() {
136 MediaCallCommand media_command;
139 bool enqueue = media_command.enqueue.has_value() && media_command.enqueue.value();
141 if (media_command.url.has_value() || media_command.file.has_value()) {
142#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
148 PlaylistItem playlist_item;
149 if (media_command.url.has_value()) {
150 playlist_item.url = *media_command.url.value();
151 delete media_command.url.value();
153 if (media_command.file.has_value()) {
154 playlist_item.file = media_command.file;
156 playlist_item.is_announcement = media_command.is_announcement;
158 if (this->
single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
164 this->volume, this->speaker_volume_applier_());
169 if (media_command.file.has_value()) {
171 }
else if (media_command.url.has_value()) {
189 if (media_command.file.has_value()) {
191 }
else if (media_command.url.has_value()) {
204 if (media_command.volume.has_value()) {
209 if (media_command.command.has_value()) {
210 switch (media_command.command.value()) {
212#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
229#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
243#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
244 if (this->
single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value()) ||
247 if (this->
single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
255 this->
set_interval(UNPAUSE_ANNOUNCEMENT_INTERVAL_ID, 50, [
this]() {
304 if (this->
single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
311 if (this->
single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
318 if (this->
single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
335#ifdef USE_OTA_STATE_LISTENER
337 ota::OTAComponent *comp) {
368 ESP_LOGE(TAG,
"The media pipeline's file reader encountered an error.");
371 ESP_LOGE(TAG,
"The media pipeline's audio decoder encountered an error.");
381 ESP_LOGE(TAG,
"The announcement pipeline's file reader encountered an error.");
384 ESP_LOGE(TAG,
"The announcement pipeline's audio decoder encountered an error.");
413 this->volume, this->speaker_volume_applier_());
414 if (playlist_item.url.has_value()) {
416 }
else if (playlist_item.file.has_value()) {
420 if (timeout_ms > 0) {
425 this->
set_timeout(NEXT_ANNOUNCEMENT_TIMEOUT_ID, timeout_ms,
433#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
461 if (playlist_item.url.has_value()) {
463 }
else if (playlist_item.file.has_value()) {
467 if (timeout_ms > 0) {
472 this->
set_timeout(NEXT_MEDIA_TIMEOUT_ID, timeout_ms,
479#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
497 if (this->state != old_state) {
501#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
523 MediaCallCommand media_command;
525 media_command.file = media_file;
526 media_command.is_announcement = announcement;
528 media_command.announce =
true;
530 media_command.announce =
false;
532 media_command.enqueue = enqueue;
542 MediaCallCommand media_command;
544 auto ann =
call.get_announcement();
545 media_command.is_announcement = ann.has_value() && *ann;
547 media_command.announce =
true;
549 media_command.announce =
false;
552 const auto &media_url =
call.get_media_url();
553 if (media_url.has_value()) {
555 new std::string(*media_url);
557 auto cmd =
call.get_command();
558 if (cmd.has_value()) {
560 media_command.enqueue =
true;
568 auto vol =
call.get_volume();
569 if (vol.has_value()) {
570 media_command.volume = vol;
576 auto cmd =
call.get_command();
577 if (cmd.has_value()) {
578 media_command.command = cmd;
579 TickType_t ticks_to_wait = portMAX_DELAY;
590 auto traits = media_player::MediaPlayerTraits();
592 traits.set_supports_pause(
true);
594#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
595 traits.set_supports_turn_off_on(
true);
602 traits.get_supported_formats().push_back(this->
media_format_.value());
607 traits.get_supported_formats().push_back(media_format);
614 VolumeRestoreState volume_restore_state;
615 volume_restore_state.volume = this->
volume;
616 volume_restore_state.is_muted = this->
is_muted_;
633 if (old_mute_state != mute_state) {
658 float bounded_volume = (
volume < SILENT_VOLUME_THRESHOLD)
void mark_failed()
Mark this component as failed.
bool cancel_interval(const char *name)
Cancel an interval function.
bool cancel_timeout(const char *name)
Cancel a timeout function.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void defer(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call with a const char* name.
void set_interval(const char *name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a const char* name.
ESPPreferenceObject make_entity_preference(uint32_t version=0)
Create a preference object for storing this entity's state/settings.
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
void add_global_state_listener(OTAGlobalStateListener *listener)
void cancel()
The media player volume was set and already sent to the speakers; it applies until the next announcem...
void item_started(bool is_announcement, bool other_audio_playing, float media_volume, F &&apply)
Called when an item starts on a playlist that holds announcements, and may hold media too.
void set_volume(float volume, F &&apply)
Stores a new announcement volume and applies it right away if it is in use.
void playlist_finished(float media_volume, F &&apply)
Called when the playlist that holds announcements has finished. Switches back to the media volume.
void end(float media_volume, F &&apply)
Switches back to the media player volume if the announcement volume is in use.
virtual void set_volume(float volume)
virtual void set_mute_state(bool mute_state)
FLAG_HAS_TRANSITION float
OTAGlobalCallback * get_global_ota_callback()
ESPHOME_LOG_TAG(TAG, "announcement_volume")
T remap(U value, U min, U max, T min_out, T max_out)
Remap value from the range (min, max) to (min_out, max_out).