Files
esphome-lsm6ds/esphome/components/speaker/media_player/speaker_media_player.h
T
b6f0bb9b6b [speaker] Add off on capability to media player (#9295)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Kevin Ahrendt <kevin.ahrendt@openhomefoundation.org>
2026-03-03 10:59:01 -05:00

174 lines
5.9 KiB
C++

#pragma once
#ifdef USE_ESP32
#include "audio_pipeline.h"
#include "esphome/components/audio/audio.h"
#include "esphome/components/media_player/media_player.h"
#include "esphome/components/speaker/speaker.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/preferences.h"
#ifdef USE_OTA_STATE_LISTENER
#include "esphome/components/ota/ota_backend.h"
#endif
#include <deque>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
namespace esphome {
namespace speaker {
struct MediaCallCommand {
optional<media_player::MediaPlayerCommand> command;
optional<float> volume;
optional<bool> announce;
optional<std::string *> url; // Must be manually deleted after receiving this struct from a queue
optional<audio::AudioFile *> file;
optional<bool> enqueue;
};
struct PlaylistItem {
optional<std::string> url;
optional<audio::AudioFile *> file;
};
struct VolumeRestoreState {
float volume;
bool is_muted;
};
class SpeakerMediaPlayer : public Component,
public media_player::MediaPlayer
#ifdef USE_OTA_STATE_LISTENER
,
public ota::OTAGlobalStateListener
#endif
{
public:
float get_setup_priority() const override { return esphome::setup_priority::PROCESSOR; }
void setup() override;
void loop() override;
#ifdef USE_OTA_STATE_LISTENER
void on_ota_global_state(ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) override;
#endif
// MediaPlayer implementations
media_player::MediaPlayerTraits get_traits() override;
bool is_muted() const override { return this->is_muted_; }
void set_buffer_size(size_t buffer_size) { this->buffer_size_ = buffer_size; }
void set_task_stack_in_psram(bool task_stack_in_psram) { this->task_stack_in_psram_ = task_stack_in_psram; }
// Percentage to increase or decrease the volume for volume up or volume down commands
void set_volume_increment(float volume_increment) { this->volume_increment_ = volume_increment; }
// Volume used initially on first boot when no volume had been previously saved
void set_volume_initial(float volume_initial) { this->volume_initial_ = volume_initial; }
void set_volume_max(float volume_max) { this->volume_max_ = volume_max; }
void set_volume_min(float volume_min) { this->volume_min_ = volume_min; }
void set_announcement_speaker(Speaker *announcement_speaker) { this->announcement_speaker_ = announcement_speaker; }
void set_announcement_format(const media_player::MediaPlayerSupportedFormat &announcement_format) {
this->announcement_format_ = announcement_format;
}
void set_media_speaker(Speaker *media_speaker) { this->media_speaker_ = media_speaker; }
void set_media_format(const media_player::MediaPlayerSupportedFormat &media_format) {
this->media_format_ = media_format;
}
Trigger<> *get_mute_trigger() { return &this->mute_trigger_; }
Trigger<> *get_unmute_trigger() { return &this->unmute_trigger_; }
Trigger<float> *get_volume_trigger() { return &this->volume_trigger_; }
void play_file(audio::AudioFile *media_file, bool announcement, bool enqueue);
void set_playlist_delay_ms(AudioPipelineType pipeline_type, uint32_t delay_ms);
protected:
// Receives commands from HA or from the voice assistant component
// Sends commands to the media_control_commanda_queue_
void control(const media_player::MediaPlayerCall &call) override;
/// @brief Updates this->volume and saves volume/mute state to flash for restortation if publish is true.
void set_volume_(float volume, bool publish = true);
/// @brief Sets the mute state. Restores previous volume if unmuting. Always saves volume/mute state to flash for
/// restoration.
/// @param mute_state If true, audio will be muted. If false, audio will be unmuted
void set_mute_state_(bool mute_state);
/// @brief Saves the current volume and mute state to the flash for restoration.
void save_volume_restore_state_();
/// Returns true if the media player has only the announcement pipeline defined, false if both the announcement and
/// media pipelines are defined.
inline bool single_pipeline_() { return (this->media_speaker_ == nullptr); }
/// Stops the media pipeline and polls until stopped to unpause it, avoiding an audible glitch.
void stop_and_unpause_media_();
// Processes commands from media_control_command_queue_.
void watch_media_commands_();
std::unique_ptr<AudioPipeline> announcement_pipeline_;
std::unique_ptr<AudioPipeline> media_pipeline_;
Speaker *media_speaker_{nullptr};
Speaker *announcement_speaker_{nullptr};
optional<media_player::MediaPlayerSupportedFormat> media_format_;
AudioPipelineState media_pipeline_state_{AudioPipelineState::STOPPED};
bool media_repeat_one_{false};
uint32_t media_playlist_delay_ms_{0};
optional<media_player::MediaPlayerSupportedFormat> announcement_format_;
AudioPipelineState announcement_pipeline_state_{AudioPipelineState::STOPPED};
bool announcement_repeat_one_{false};
uint32_t announcement_playlist_delay_ms_{0};
QueueHandle_t media_control_command_queue_;
std::deque<PlaylistItem> announcement_playlist_;
std::deque<PlaylistItem> media_playlist_;
size_t buffer_size_;
bool task_stack_in_psram_;
bool is_paused_{false};
bool is_muted_{false};
#ifdef USE_SPEAKER_MEDIA_PLAYER_ON_OFF
bool is_turn_off_{false};
#endif
uint8_t unpause_media_remaining_{0};
uint8_t unpause_announcement_remaining_{0};
// The amount to change the volume on volume up/down commands
float volume_increment_;
// The initial volume used by Setup when no previous volume was saved
float volume_initial_;
float volume_max_;
float volume_min_;
// Used to save volume/mute state for restoration on reboot
ESPPreferenceObject pref_;
Trigger<> mute_trigger_;
Trigger<> unmute_trigger_;
Trigger<float> volume_trigger_;
};
} // namespace speaker
} // namespace esphome
#endif