ESPHome 2025.5.0
Loading...
Searching...
No Matches
mixer_speaker.h
Go to the documentation of this file.
1#pragma once
2
3#ifdef USE_ESP32
4
8
10
11#include <freertos/event_groups.h>
12#include <freertos/FreeRTOS.h>
13
14namespace esphome {
15namespace mixer_speaker {
16
17/* Classes for mixing several source speaker audio streams and writing it to another speaker component.
18 * - Volume controls are passed through to the output speaker
19 * - Directly handles pausing at the SourceSpeaker level; pause state is not passed through to the output speaker.
20 * - Audio sent to the SourceSpeaker's must have 16 bits per sample.
21 * - Audio sent to the SourceSpeaker can have any number of channels. They are duplicated or ignored as needed to match
22 * the number of channels required for the output speaker.
23 * - In queue mode, the audio sent to the SoureSpeakers can have different sample rates.
24 * - In non-queue mode, the audio sent to the SourceSpeakers must have the same sample rates.
25 * - SourceSpeaker has an internal ring buffer. It also allocates a shared_ptr for an AudioTranserBuffer object.
26 * - Audio Data Flow:
27 * - Audio data played on a SourceSpeaker first writes to its internal ring buffer.
28 * - MixerSpeaker task temporarily takes shared ownership of each SourceSpeaker's AudioTransferBuffer.
29 * - MixerSpeaker calls SourceSpeaker's `process_data_from_source`, which tranfers audio from the SourceSpeaker's
30 * ring buffer to its AudioTransferBuffer. Audio ducking is applied at this step.
31 * - In queue mode, MixerSpeaker prioritizes the earliest configured SourceSpeaker with audio data. Audio data is
32 * sent to the output speaker.
33 * - In non-queue mode, MixerSpeaker adds all the audio data in each SourceSpeaker into one stream that is written
34 * to the output speaker.
35 */
36
37class MixerSpeaker;
38
40 public:
41 void dump_config() override;
42 void setup() override;
43 void loop() override;
44
45 size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) override;
46 size_t play(const uint8_t *data, size_t length) override { return this->play(data, length, 0); }
47
48 void start() override;
49 void stop() override;
50 void finish() override;
51
52 bool has_buffered_data() const override;
53
55 void set_mute_state(bool mute_state) override;
56 bool get_mute_state() override;
57
59 void set_volume(float volume) override;
60 float get_volume() override;
61
62 void set_pause_state(bool pause_state) override { this->pause_state_ = pause_state; }
63 bool get_pause_state() const override { return this->pause_state_; }
64
68 size_t process_data_from_source(TickType_t ticks_to_wait);
69
73 void apply_ducking(uint8_t decibel_reduction, uint32_t duration);
74
75 void set_buffer_duration(uint32_t buffer_duration_ms) { this->buffer_duration_ms_ = buffer_duration_ms; }
76 void set_parent(MixerSpeaker *parent) { this->parent_ = parent; }
77 void set_timeout(uint32_t ms) { this->timeout_ms_ = ms; }
78
79 std::weak_ptr<audio::AudioSourceTransferBuffer> get_transfer_buffer() { return this->transfer_buffer_; }
80
81 protected:
82 friend class MixerSpeaker;
83 esp_err_t start_();
84 void stop_();
85
95 static void duck_samples(int16_t *input_buffer, uint32_t input_samples_to_duck, int8_t *current_ducking_db_reduction,
96 uint32_t *ducking_transition_samples_remaining, uint32_t samples_per_ducking_step,
97 int8_t db_change_per_ducking_step);
98
100
101 std::shared_ptr<audio::AudioSourceTransferBuffer> transfer_buffer_;
102 std::weak_ptr<RingBuffer> ring_buffer_;
103
107 bool stop_gracefully_{false};
108
109 bool pause_state_{false};
110
116
118};
119
120class MixerSpeaker : public Component {
121 public:
122 void dump_config() override;
123 void setup() override;
124 void loop() override;
125
126 void add_source_speaker(SourceSpeaker *source_speaker) { this->source_speakers_.push_back(source_speaker); }
127
135 esp_err_t start(audio::AudioStreamInfo &stream_info);
136
137 void stop();
138
139 void set_output_channels(uint8_t output_channels) { this->output_channels_ = output_channels; }
140 void set_output_speaker(speaker::Speaker *speaker) { this->output_speaker_ = speaker; }
141 void set_queue_mode(bool queue_mode) { this->queue_mode_ = queue_mode; }
142 void set_task_stack_in_psram(bool task_stack_in_psram) { this->task_stack_in_psram_ = task_stack_in_psram; }
143
145
146 protected:
155 static void copy_frames(const int16_t *input_buffer, audio::AudioStreamInfo input_stream_info, int16_t *output_buffer,
156 audio::AudioStreamInfo output_stream_info, uint32_t frames_to_transfer);
157
169 static void mix_audio_samples(const int16_t *primary_buffer, audio::AudioStreamInfo primary_stream_info,
170 const int16_t *secondary_buffer, audio::AudioStreamInfo secondary_stream_info,
171 int16_t *output_buffer, audio::AudioStreamInfo output_stream_info,
172 uint32_t frames_to_mix);
173
174 static void audio_mixer_task(void *params);
175
180 esp_err_t start_task_();
181
184 esp_err_t delete_task_();
185
186 EventGroupHandle_t event_group_{nullptr};
187
188 std::vector<SourceSpeaker *> source_speakers_;
190
194
195 bool task_created_{false};
196
197 TaskHandle_t task_handle_{nullptr};
198 StaticTask_t task_stack_;
199 StackType_t *task_stack_buffer_{nullptr};
200
202};
203
204} // namespace mixer_speaker
205} // namespace esphome
206
207#endif
esp_err_t start_task_()
Starts the mixer task after allocating memory for the task stack.
esp_err_t delete_task_()
If the task is stopped, it sets the task handle to the nullptr and deallocates its stack.
esp_err_t start(audio::AudioStreamInfo &stream_info)
Starts the mixer task.
void set_output_channels(uint8_t output_channels)
void add_source_speaker(SourceSpeaker *source_speaker)
void set_task_stack_in_psram(bool task_stack_in_psram)
speaker::Speaker * get_output_speaker() const
std::vector< SourceSpeaker * > source_speakers_
void set_output_speaker(speaker::Speaker *speaker)
static void mix_audio_samples(const int16_t *primary_buffer, audio::AudioStreamInfo primary_stream_info, const int16_t *secondary_buffer, audio::AudioStreamInfo secondary_stream_info, int16_t *output_buffer, audio::AudioStreamInfo output_stream_info, uint32_t frames_to_mix)
Mixes the primary and secondary streams taking into account the number of channels in each stream.
static void copy_frames(const int16_t *input_buffer, audio::AudioStreamInfo input_stream_info, int16_t *output_buffer, audio::AudioStreamInfo output_stream_info, uint32_t frames_to_transfer)
Copies audio frames from the input buffer to the output buffer taking into account the number of chan...
static void audio_mixer_task(void *params)
optional< audio::AudioStreamInfo > audio_stream_info_
std::shared_ptr< audio::AudioSourceTransferBuffer > transfer_buffer_
void set_mute_state(bool mute_state) override
Mute state changes are passed to the parent's output speaker.
void set_buffer_duration(uint32_t buffer_duration_ms)
static void duck_samples(int16_t *input_buffer, uint32_t input_samples_to_duck, int8_t *current_ducking_db_reduction, uint32_t *ducking_transition_samples_remaining, uint32_t samples_per_ducking_step, int8_t db_change_per_ducking_step)
Ducks audio samples by a specified amount.
size_t process_data_from_source(TickType_t ticks_to_wait)
Transfers audio from the ring buffer into the transfer buffer.
bool get_pause_state() const override
std::weak_ptr< audio::AudioSourceTransferBuffer > get_transfer_buffer()
void apply_ducking(uint8_t decibel_reduction, uint32_t duration)
Sets the ducking level for the source speaker.
std::weak_ptr< RingBuffer > ring_buffer_
size_t play(const uint8_t *data, size_t length) override
size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) override
void set_parent(MixerSpeaker *parent)
void set_volume(float volume) override
Volume state changes are passed to the parent's output speaker.
void set_pause_state(bool pause_state) override
uint8_t duration
Definition msa3xx.h:0
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint16_t length
Definition tt21100.cpp:0