ESPHome 2026.5.3
Loading...
Searching...
No Matches
audio_transfer_buffer.h
Go to the documentation of this file.
1#pragma once
2
3#ifdef USE_ESP32
6
7#ifdef USE_SPEAKER
9#endif
10
11#include "esp_err.h"
12
13#include <freertos/FreeRTOS.h>
14
15namespace esphome::audio {
16
19 public:
20 virtual size_t audio_sink_write(uint8_t *data, size_t length, TickType_t ticks_to_wait) = 0;
21};
22
24 /*
25 * @brief Class that facilitates tranferring data between a buffer and an audio source or sink.
26 * The transfer buffer is a typical C array that temporarily holds data for processing in other audio components.
27 * Both sink and source transfer buffers can use a ring buffer as the sink/source.
28 * - The ring buffer is stored in a shared_ptr, so destroying the transfer buffer object will release ownership.
29 */
30 public:
33
35 uint8_t *get_buffer_start() const { return this->data_start_; }
36
38 uint8_t *get_buffer_end() const { return this->data_start_ + this->buffer_length_; }
39
42 void decrease_buffer_length(size_t bytes);
43
46 void increase_buffer_length(size_t bytes);
47
49 size_t available() const { return this->buffer_length_; }
50
52 size_t capacity() const { return this->buffer_size_; }
53
55 size_t free() const;
56
58 virtual void clear_buffered_data();
59
62 virtual bool has_buffered_data() const;
63
67 bool reallocate(size_t new_buffer_size);
68
69 protected:
73 bool allocate_buffer_(size_t buffer_size);
74
76 void deallocate_buffer_();
77
78 // A possible source or sink for the transfer buffer
79 std::shared_ptr<ring_buffer::RingBuffer> ring_buffer_;
80
81 uint8_t *buffer_{nullptr};
82 uint8_t *data_start_{nullptr};
83
84 size_t buffer_size_{0};
85 size_t buffer_length_{0};
86};
87
89 /*
90 * @brief A class that implements a transfer buffer for audio sinks.
91 * Supports writing processed data in the transfer buffer to a ring buffer or a speaker component.
92 */
93 public:
97 static std::unique_ptr<AudioSinkTransferBuffer> create(size_t buffer_size);
98
104 size_t transfer_data_to_sink(TickType_t ticks_to_wait, bool post_shift = true);
105
108 void set_sink(const std::weak_ptr<ring_buffer::RingBuffer> &ring_buffer) { this->ring_buffer_ = ring_buffer.lock(); }
109
110#ifdef USE_SPEAKER
113 void set_sink(speaker::Speaker *speaker) { this->speaker_ = speaker; }
114#endif
115
118 void set_sink(AudioSinkCallback *callback) { this->sink_callback_ = callback; }
119
120 void clear_buffered_data() override;
121
122 bool has_buffered_data() const override;
123
124 protected:
125#ifdef USE_SPEAKER
127#endif
129};
130
134 public:
135 virtual ~AudioReadableBuffer() = default;
136
138 virtual const uint8_t *data() const = 0;
139
141 virtual size_t available() const = 0;
142
144 virtual size_t free() const { return 0; }
145
148 virtual void consume(size_t bytes) = 0;
149
151 virtual bool has_buffered_data() const = 0;
152
157 virtual size_t fill(TickType_t ticks_to_wait, bool pre_shift) { return 0; }
158 size_t fill(TickType_t ticks_to_wait) { return this->fill(ticks_to_wait, true); }
159};
160
162 /*
163 * @brief A class that implements a transfer buffer for audio sources.
164 * Supports reading audio data from a ring buffer into the transfer buffer for processing.
165 * Implements AudioReadableBuffer for use by consumers that only need read access.
166 */
167 public:
171 static std::unique_ptr<AudioSourceTransferBuffer> create(size_t buffer_size);
172
178 size_t transfer_data_from_source(TickType_t ticks_to_wait, bool pre_shift = true);
179
182 void set_source(const std::weak_ptr<ring_buffer::RingBuffer> &ring_buffer) {
183 this->ring_buffer_ = ring_buffer.lock();
184 };
185
186 // AudioReadableBuffer interface
187 const uint8_t *data() const override { return this->data_start_; }
188 size_t available() const override { return this->buffer_length_; }
189 size_t free() const override;
190 void consume(size_t bytes) override { this->decrease_buffer_length(bytes); }
191 bool has_buffered_data() const override;
192 size_t fill(TickType_t ticks_to_wait, bool pre_shift) override {
193 return this->transfer_data_from_source(ticks_to_wait, pre_shift);
194 }
195};
196
200 public:
204 void set_data(const uint8_t *data, size_t length);
205
206 // AudioReadableBuffer interface
207 const uint8_t *data() const override { return this->data_start_; }
208 size_t available() const override { return this->length_; }
209 void consume(size_t bytes) override;
210 bool has_buffered_data() const override { return this->length_ > 0; }
211
212 protected:
213 const uint8_t *data_start_{nullptr};
214 size_t length_{0};
215};
216
228 public:
230 static constexpr size_t MAX_ALIGNMENT_BYTES = 8;
231
239 static std::unique_ptr<RingBufferAudioSource> create(std::shared_ptr<ring_buffer::RingBuffer> ring_buffer,
240 size_t max_fill_bytes, uint8_t alignment_bytes = 1);
241
242 ~RingBufferAudioSource() override;
243
244 // AudioReadableBuffer interface
245 const uint8_t *data() const override { return this->current_data_; }
246 size_t available() const override { return this->current_available_; }
247 void consume(size_t bytes) override;
248 bool has_buffered_data() const override;
251 size_t fill(TickType_t ticks_to_wait, bool pre_shift) override;
252
258 uint8_t *mutable_data() { return this->current_data_; }
259
260 protected:
263 explicit RingBufferAudioSource(std::shared_ptr<ring_buffer::RingBuffer> ring_buffer, size_t max_fill_bytes,
264 uint8_t alignment_bytes)
265 : ring_buffer_(std::move(ring_buffer)), max_fill_bytes_(max_fill_bytes), alignment_bytes_(alignment_bytes) {}
266
269 void release_item_();
270
271 std::shared_ptr<ring_buffer::RingBuffer> ring_buffer_;
273
274 void *acquired_item_{nullptr};
275 uint8_t *current_data_{nullptr};
276
277 // Sub-frame trailing bytes inside the held item that will be copied to splice_buffer_ on release.
278 uint8_t *item_trailing_ptr_{nullptr};
279
280 // After the currently-exposed splice frame is consumed, fill() will promote this region (the aligned
281 // remainder of the new chunk) to the exposed region. queued_length_ == 0 when nothing is queued.
282 uint8_t *queued_data_{nullptr};
283
284 // Splice buffer holds the start of a partial frame whose remainder lives at the head of the next
285 // chunk. While splice_length_ > 0, the buffer is incomplete and waiting for completion bytes.
287
289 size_t queued_length_{0};
290
291 // item_trailing_length_ and splice_length_ are bounded by MAX_ALIGNMENT_BYTES.
294 uint8_t splice_length_{0};
295};
296
297} // namespace esphome::audio
298
299#endif
Abstract interface for reading audio data from a buffer.
virtual const uint8_t * data() const =0
Returns a pointer to the start of readable data.
virtual size_t fill(TickType_t ticks_to_wait, bool pre_shift)
Refills the buffer from its source.
virtual size_t available() const =0
Returns the number of bytes available to read.
virtual size_t free() const
Returns the number of free bytes available to write. Defaults to 0 for read-only buffers.
virtual ~AudioReadableBuffer()=default
size_t fill(TickType_t ticks_to_wait)
virtual bool has_buffered_data() const =0
Tests if there is any buffered data.
virtual void consume(size_t bytes)=0
Advances past consumed data.
Abstract interface for writing decoded audio data to a sink.
virtual size_t audio_sink_write(uint8_t *data, size_t length, TickType_t ticks_to_wait)=0
size_t transfer_data_to_sink(TickType_t ticks_to_wait, bool post_shift=true)
Writes any available data in the transfer buffer to the sink.
void set_sink(AudioSinkCallback *callback)
Adds a callback as the transfer buffer's sink.
void set_sink(speaker::Speaker *speaker)
Adds a speaker as the transfer buffer's sink.
static std::unique_ptr< AudioSinkTransferBuffer > create(size_t buffer_size)
Creates a new sink transfer buffer.
void set_sink(const std::weak_ptr< ring_buffer::RingBuffer > &ring_buffer)
Adds a ring buffer as the transfer buffer's sink.
size_t fill(TickType_t ticks_to_wait, bool pre_shift) override
void set_source(const std::weak_ptr< ring_buffer::RingBuffer > &ring_buffer)
Adds a ring buffer as the transfer buffer's source.
size_t transfer_data_from_source(TickType_t ticks_to_wait, bool pre_shift=true)
Reads any available data from the source into the transfer buffer.
static std::unique_ptr< AudioSourceTransferBuffer > create(size_t buffer_size)
Creates a new source transfer buffer.
size_t free() const
Returns the transfer buffer's currrently free bytes available to write.
virtual bool has_buffered_data() const
Tests if there is any data in the tranfer buffer or the source/sink.
virtual void clear_buffered_data()
Clears data in the transfer buffer and, if possible, the source/sink.
~AudioTransferBuffer()
Destructor that deallocates the transfer buffer.
uint8_t * get_buffer_end() const
Returns a pointer to the end of the transfer buffer where free() bytes of new data can be written.
void increase_buffer_length(size_t bytes)
Updates the internal state of the transfer buffer.
bool reallocate(size_t new_buffer_size)
Reallocates the transfer buffer, preserving any existing data.
bool allocate_buffer_(size_t buffer_size)
Allocates the transfer buffer in external memory, if available.
uint8_t * get_buffer_start() const
Returns a pointer to the start of the transfer buffer where available() bytes of existing data can be...
void decrease_buffer_length(size_t bytes)
Updates the internal state of the transfer buffer.
size_t available() const
Returns the transfer buffer's currently available bytes to read.
std::shared_ptr< ring_buffer::RingBuffer > ring_buffer_
size_t capacity() const
Returns the transfer buffers allocated bytes.
void deallocate_buffer_()
Deallocates the buffer and resets the class variables.
A lightweight read-only audio buffer for const data sources (e.g., flash memory).
void set_data(const uint8_t *data, size_t length)
Sets the data pointer and length for the buffer.
const uint8_t * data() const override
Zero-copy audio source that reads directly from a ring buffer's internal storage.
uint8_t splice_buffer_[MAX_ALIGNMENT_BYTES]
void release_item_()
Releases the currently held ring buffer item, first copying any trailing sub-frame bytes into the spl...
size_t fill(TickType_t ticks_to_wait, bool pre_shift) override
pre_shift is ignored: there is no intermediate transfer buffer to compact, so an unconsumed exposure ...
static constexpr size_t MAX_ALIGNMENT_BYTES
Maximum supported alignment. Sized to cover 32-bit samples across up to 2 channels (8 bytes).
static std::unique_ptr< RingBufferAudioSource > create(std::shared_ptr< ring_buffer::RingBuffer > ring_buffer, size_t max_fill_bytes, uint8_t alignment_bytes=1)
Creates a new ring-buffer-backed audio source after validating its parameters.
RingBufferAudioSource(std::shared_ptr< ring_buffer::RingBuffer > ring_buffer, size_t max_fill_bytes, uint8_t alignment_bytes)
Constructs a new ring-buffer-backed audio source.
uint8_t * mutable_data()
Returns a mutable pointer to the currently exposed audio data.
std::shared_ptr< ring_buffer::RingBuffer > ring_buffer_
const uint8_t * data() const override
uint16_t length
Definition tt21100.cpp:0