ESPHome 2026.3.0-dev
Loading...
Searching...
No Matches
audio_transfer_buffer.cpp
Go to the documentation of this file.
2
3#ifdef USE_ESP32
4
5#include <cstring>
6
8
9namespace esphome {
10namespace audio {
11
13
14std::unique_ptr<AudioSinkTransferBuffer> AudioSinkTransferBuffer::create(size_t buffer_size) {
15 std::unique_ptr<AudioSinkTransferBuffer> sink_buffer = make_unique<AudioSinkTransferBuffer>();
16
17 if (!sink_buffer->allocate_buffer_(buffer_size)) {
18 return nullptr;
19 }
20
21 return sink_buffer;
22}
23
24std::unique_ptr<AudioSourceTransferBuffer> AudioSourceTransferBuffer::create(size_t buffer_size) {
25 std::unique_ptr<AudioSourceTransferBuffer> source_buffer = make_unique<AudioSourceTransferBuffer>();
26
27 if (!source_buffer->allocate_buffer_(buffer_size)) {
28 return nullptr;
29 }
30
31 return source_buffer;
32}
33
35 if (this->buffer_size_ == 0) {
36 return 0;
37 }
38 return this->buffer_size_ - (this->buffer_length_ + (this->data_start_ - this->buffer_));
39}
40
42 this->buffer_length_ -= bytes;
43 if (this->buffer_length_ > 0) {
44 this->data_start_ += bytes;
45 } else {
46 // All the data in the buffer has been consumed, reset the start pointer
47 this->data_start_ = this->buffer_;
48 }
49}
50
51void AudioTransferBuffer::increase_buffer_length(size_t bytes) { this->buffer_length_ += bytes; }
52
54 this->buffer_length_ = 0;
55 if (this->ring_buffer_.use_count() > 0) {
56 this->ring_buffer_->reset();
57 }
58}
59
61 this->buffer_length_ = 0;
62 if (this->ring_buffer_.use_count() > 0) {
63 this->ring_buffer_->reset();
64 }
65#ifdef USE_SPEAKER
66 if (this->speaker_ != nullptr) {
67 this->speaker_->stop();
68 }
69#endif
70}
71
73 if (this->ring_buffer_.use_count() > 0) {
74 return ((this->ring_buffer_->available() > 0) || (this->available() > 0));
75 }
76 return (this->available() > 0);
77}
78
79bool AudioTransferBuffer::reallocate(size_t new_buffer_size) {
80 if (this->buffer_ == nullptr) {
81 return this->allocate_buffer_(new_buffer_size);
82 }
83
84 if (new_buffer_size < this->buffer_length_) {
85 // New size is too small to hold existing data
86 return false;
87 }
88
89 // Shift existing data to the start of the buffer so realloc preserves it
90 if ((this->buffer_length_ > 0) && (this->data_start_ != this->buffer_)) {
91 std::memmove(this->buffer_, this->data_start_, this->buffer_length_);
92 this->data_start_ = this->buffer_;
93 }
94
95 RAMAllocator<uint8_t> allocator;
96 uint8_t *new_buffer = allocator.reallocate(this->buffer_, new_buffer_size);
97 if (new_buffer == nullptr) {
98 // Reallocation failed, but the original buffer is still valid
99 return false;
100 }
101
102 this->buffer_ = new_buffer;
103 this->data_start_ = this->buffer_;
104 this->buffer_size_ = new_buffer_size;
105 return true;
106}
107
109 this->buffer_size_ = buffer_size;
110
111 RAMAllocator<uint8_t> allocator;
112
113 this->buffer_ = allocator.allocate(this->buffer_size_);
114 if (this->buffer_ == nullptr) {
115 return false;
116 }
117
118 this->data_start_ = this->buffer_;
119 this->buffer_length_ = 0;
120
121 return true;
122}
123
125 if (this->buffer_ != nullptr) {
126 RAMAllocator<uint8_t> allocator;
127 allocator.deallocate(this->buffer_, this->buffer_size_);
128 this->buffer_ = nullptr;
129 this->data_start_ = nullptr;
130 }
131
132 this->buffer_size_ = 0;
133 this->buffer_length_ = 0;
134}
135
136size_t AudioSourceTransferBuffer::transfer_data_from_source(TickType_t ticks_to_wait, bool pre_shift) {
137 if (pre_shift) {
138 // Shift data in buffer to start
139 if (this->buffer_length_ > 0) {
140 std::memmove(this->buffer_, this->data_start_, this->buffer_length_);
141 }
142 this->data_start_ = this->buffer_;
143 }
144
145 size_t bytes_to_read = AudioTransferBuffer::free();
146 size_t bytes_read = 0;
147 if (bytes_to_read > 0) {
148 if (this->ring_buffer_.use_count() > 0) {
149 bytes_read = this->ring_buffer_->read((void *) this->get_buffer_end(), bytes_to_read, ticks_to_wait);
150 }
151
152 this->increase_buffer_length(bytes_read);
153 }
154 return bytes_read;
155}
156
157size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait, bool post_shift) {
158 size_t bytes_written = 0;
159 if (this->available()) {
160#ifdef USE_SPEAKER
161 if (this->speaker_ != nullptr) {
162 bytes_written = this->speaker_->play(this->data_start_, this->available(), ticks_to_wait);
163 } else
164#endif
165 if (this->ring_buffer_.use_count() > 0) {
166 bytes_written =
167 this->ring_buffer_->write_without_replacement((void *) this->data_start_, this->available(), ticks_to_wait);
168 } else if (this->sink_callback_ != nullptr) {
169 bytes_written = this->sink_callback_->audio_sink_write(this->data_start_, this->available(), ticks_to_wait);
170 }
171
172 this->decrease_buffer_length(bytes_written);
173 }
174
175 if (post_shift) {
176 // Shift unwritten data to the start of the buffer
177 std::memmove(this->buffer_, this->data_start_, this->buffer_length_);
178 this->data_start_ = this->buffer_;
179 }
180
181 return bytes_written;
182}
183
185#ifdef USE_SPEAKER
186 if (this->speaker_ != nullptr) {
187 return (this->speaker_->has_buffered_data() || (this->available() > 0));
188 }
189#endif
190 if (this->ring_buffer_.use_count() > 0) {
191 return ((this->ring_buffer_->available() > 0) || (this->available() > 0));
192 }
193 return (this->available() > 0);
194}
195
197
199
200void ConstAudioSourceBuffer::set_data(const uint8_t *data, size_t length) {
201 this->data_start_ = data;
202 this->length_ = length;
203}
204
206 bytes = std::min(bytes, this->length_);
207 this->length_ -= bytes;
208 this->data_start_ += bytes;
209}
210
211} // namespace audio
212} // namespace esphome
213
214#endif
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1794
T * reallocate(T *p, size_t n)
Definition helpers.h:1830
void deallocate(T *p, size_t n)
Definition helpers.h:1849
T * allocate(size_t n)
Definition helpers.h:1811
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.
static std::unique_ptr< AudioSinkTransferBuffer > create(size_t buffer_size)
Creates a new sink transfer buffer.
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.
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< RingBuffer > ring_buffer_
void deallocate_buffer_()
Deallocates the buffer and resets the class variables.
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
virtual size_t play(const uint8_t *data, size_t length)=0
Plays the provided audio data.
virtual bool has_buffered_data() const =0
virtual void stop()=0
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint16_t length
Definition tt21100.cpp:0