ESPHome 2025.5.0
Loading...
Searching...
No Matches
audio_transfer_buffer.cpp
Go to the documentation of this file.
2
3#ifdef USE_ESP32
4
6
7namespace esphome {
8namespace audio {
9
11
12std::unique_ptr<AudioSinkTransferBuffer> AudioSinkTransferBuffer::create(size_t buffer_size) {
13 std::unique_ptr<AudioSinkTransferBuffer> sink_buffer = make_unique<AudioSinkTransferBuffer>();
14
15 if (!sink_buffer->allocate_buffer_(buffer_size)) {
16 return nullptr;
17 }
18
19 return sink_buffer;
20}
21
22std::unique_ptr<AudioSourceTransferBuffer> AudioSourceTransferBuffer::create(size_t buffer_size) {
23 std::unique_ptr<AudioSourceTransferBuffer> source_buffer = make_unique<AudioSourceTransferBuffer>();
24
25 if (!source_buffer->allocate_buffer_(buffer_size)) {
26 return nullptr;
27 }
28
29 return source_buffer;
30}
31
33 if (this->buffer_size_ == 0) {
34 return 0;
35 }
36 return this->buffer_size_ - (this->buffer_length_ + (this->data_start_ - this->buffer_));
37}
38
40 this->buffer_length_ -= bytes;
41 if (this->buffer_length_ > 0) {
42 this->data_start_ += bytes;
43 } else {
44 // All the data in the buffer has been consumed, reset the start pointer
45 this->data_start_ = this->buffer_;
46 }
47}
48
49void AudioTransferBuffer::increase_buffer_length(size_t bytes) { this->buffer_length_ += bytes; }
50
52 this->buffer_length_ = 0;
53 if (this->ring_buffer_.use_count() > 0) {
54 this->ring_buffer_->reset();
55 }
56}
57
59 this->buffer_length_ = 0;
60 if (this->ring_buffer_.use_count() > 0) {
61 this->ring_buffer_->reset();
62 }
63#ifdef USE_SPEAKER
64 if (this->speaker_ != nullptr) {
65 this->speaker_->stop();
66 }
67#endif
68}
69
71 if (this->ring_buffer_.use_count() > 0) {
72 return ((this->ring_buffer_->available() > 0) || (this->available() > 0));
73 }
74 return (this->available() > 0);
75}
76
77bool AudioTransferBuffer::reallocate(size_t new_buffer_size) {
78 if (this->buffer_length_ > 0) {
79 // Buffer currently has data, so reallocation is impossible
80 return false;
81 }
82 this->deallocate_buffer_();
83 return this->allocate_buffer_(new_buffer_size);
84}
85
86bool AudioTransferBuffer::allocate_buffer_(size_t buffer_size) {
87 this->buffer_size_ = buffer_size;
88
90
91 this->buffer_ = allocator.allocate(this->buffer_size_);
92 if (this->buffer_ == nullptr) {
93 return false;
94 }
95
96 this->data_start_ = this->buffer_;
97 this->buffer_length_ = 0;
98
99 return true;
100}
101
103 if (this->buffer_ != nullptr) {
105 allocator.deallocate(this->buffer_, this->buffer_size_);
106 this->buffer_ = nullptr;
107 this->data_start_ = nullptr;
108 }
109
110 this->buffer_size_ = 0;
111 this->buffer_length_ = 0;
112}
113
114size_t AudioSourceTransferBuffer::transfer_data_from_source(TickType_t ticks_to_wait, bool pre_shift) {
115 if (pre_shift) {
116 // Shift data in buffer to start
117 if (this->buffer_length_ > 0) {
118 memmove(this->buffer_, this->data_start_, this->buffer_length_);
119 }
120 this->data_start_ = this->buffer_;
121 }
122
123 size_t bytes_to_read = this->free();
124 size_t bytes_read = 0;
125 if (bytes_to_read > 0) {
126 if (this->ring_buffer_.use_count() > 0) {
127 bytes_read = this->ring_buffer_->read((void *) this->get_buffer_end(), bytes_to_read, ticks_to_wait);
128 }
129
130 this->increase_buffer_length(bytes_read);
131 }
132 return bytes_read;
133}
134
135size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait, bool post_shift) {
136 size_t bytes_written = 0;
137 if (this->available()) {
138#ifdef USE_SPEAKER
139 if (this->speaker_ != nullptr) {
140 bytes_written = this->speaker_->play(this->data_start_, this->available(), ticks_to_wait);
141 } else
142#endif
143 if (this->ring_buffer_.use_count() > 0) {
144 bytes_written =
145 this->ring_buffer_->write_without_replacement((void *) this->data_start_, this->available(), ticks_to_wait);
146 }
147
148 this->decrease_buffer_length(bytes_written);
149 }
150
151 if (post_shift) {
152 // Shift unwritten data to the start of the buffer
153 memmove(this->buffer_, this->data_start_, this->buffer_length_);
154 this->data_start_ = this->buffer_;
155 }
156
157 return bytes_written;
158}
159
161#ifdef USE_SPEAKER
162 if (this->speaker_ != nullptr) {
163 return (this->speaker_->has_buffered_data() || (this->available() > 0));
164 }
165#endif
166 if (this->ring_buffer_.use_count() > 0) {
167 return ((this->ring_buffer_->available() > 0) || (this->available() > 0));
168 }
169 return (this->available() > 0);
170}
171
172} // namespace audio
173} // namespace esphome
174
175#endif
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:683
void deallocate(T *p, size_t n)
Definition helpers.h:741
T * allocate(size_t n)
Definition helpers.h:703
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 sink 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)
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.
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
std::unique_ptr< T > make_unique(Args &&...args)
Definition helpers.h:85