ESPHome  2025.2.0
audio_transfer_buffer.cpp
Go to the documentation of this file.
2 
3 #ifdef USE_ESP32
4 
5 #include "esphome/core/helpers.h"
6 
7 namespace esphome {
8 namespace audio {
9 
11 
12 std::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 
22 std::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 
32 size_t AudioTransferBuffer::free() const {
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  this->data_start_ += bytes;
42 }
43 
45 
47  this->buffer_length_ = 0;
48  if (this->ring_buffer_.use_count() > 0) {
49  this->ring_buffer_->reset();
50  }
51 }
52 
54  this->buffer_length_ = 0;
55  if (this->ring_buffer_.use_count() > 0) {
56  this->ring_buffer_->reset();
57  }
58 #ifdef USE_SPEAKER
59  if (this->speaker_ != nullptr) {
60  this->speaker_->stop();
61  }
62 #endif
63 }
64 
66  if (this->ring_buffer_.use_count() > 0) {
67  return ((this->ring_buffer_->available() > 0) || (this->available() > 0));
68  }
69  return (this->available() > 0);
70 }
71 
72 bool AudioTransferBuffer::reallocate(size_t new_buffer_size) {
73  if (this->buffer_length_ > 0) {
74  // Already has data in the buffer, fail
75  return false;
76  }
77  this->deallocate_buffer_();
78  return this->allocate_buffer_(new_buffer_size);
79 }
80 
81 bool AudioTransferBuffer::allocate_buffer_(size_t buffer_size) {
82  this->buffer_size_ = buffer_size;
83 
85 
86  this->buffer_ = allocator.allocate(this->buffer_size_);
87  if (this->buffer_ == nullptr) {
88  return false;
89  }
90 
91  this->data_start_ = this->buffer_;
92  this->buffer_length_ = 0;
93 
94  return true;
95 }
96 
98  if (this->buffer_ != nullptr) {
100  allocator.deallocate(this->buffer_, this->buffer_size_);
101  this->buffer_ = nullptr;
102  this->data_start_ = nullptr;
103  }
104 
105  this->buffer_size_ = 0;
106  this->buffer_length_ = 0;
107 }
108 
110  // Shift data in buffer to start
111  if (this->buffer_length_ > 0) {
112  memmove(this->buffer_, this->data_start_, this->buffer_length_);
113  }
114  this->data_start_ = this->buffer_;
115 
116  size_t bytes_to_read = this->free();
117  size_t bytes_read = 0;
118  if (bytes_to_read > 0) {
119  if (this->ring_buffer_.use_count() > 0) {
120  bytes_read = this->ring_buffer_->read((void *) this->get_buffer_end(), bytes_to_read, ticks_to_wait);
121  }
122 
123  this->increase_buffer_length(bytes_read);
124  }
125  return bytes_read;
126 }
127 
128 size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait) {
129  size_t bytes_written = 0;
130  if (this->available()) {
131 #ifdef USE_SPEAKER
132  if (this->speaker_ != nullptr) {
133  bytes_written = this->speaker_->play(this->data_start_, this->available(), ticks_to_wait);
134  } else
135 #endif
136  if (this->ring_buffer_.use_count() > 0) {
137  bytes_written =
138  this->ring_buffer_->write_without_replacement((void *) this->data_start_, this->available(), ticks_to_wait);
139  }
140 
141  this->decrease_buffer_length(bytes_written);
142 
143  // Shift unwritten data to the start of the buffer
144  memmove(this->buffer_, this->data_start_, this->buffer_length_);
145  this->data_start_ = this->buffer_;
146  }
147  return bytes_written;
148 }
149 
151 #ifdef USE_SPEAKER
152  if (this->speaker_ != nullptr) {
153  return (this->speaker_->has_buffered_data() || (this->available() > 0));
154  }
155 #endif
156  if (this->ring_buffer_.use_count() > 0) {
157  return ((this->ring_buffer_->available() > 0) || (this->available() > 0));
158  }
159  return (this->available() > 0);
160 }
161 
162 } // namespace audio
163 } // namespace esphome
164 
165 #endif
void deallocate_buffer_()
Deallocates the buffer and resets the class variables.
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...
static std::unique_ptr< AudioSinkTransferBuffer > create(size_t buffer_size)
Creates a new sink transfer buffer.
virtual bool has_buffered_data() const
Tests if there is any data in the tranfer buffer or the source/sink.
bool allocate_buffer_(size_t buffer_size)
Allocates the transfer buffer in external memory, if available.
T * allocate(size_t n)
Definition: helpers.h:703
void decrease_buffer_length(size_t bytes)
Updates the internal state of the transfer buffer.
size_t transfer_data_to_sink(TickType_t ticks_to_wait)
Writes any available data in the transfer buffer to the sink.
size_t available() const
Returns the transfer buffer&#39;s currently available bytes to read.
static std::unique_ptr< AudioSourceTransferBuffer > create(size_t buffer_size)
Creates a new source transfer buffer.
size_t free() const
Returns the transfer buffer&#39;s currrently free bytes available to write.
bool reallocate(size_t new_buffer_size)
void deallocate(T *p, size_t n)
Definition: helpers.h:720
void increase_buffer_length(size_t bytes)
Updates the internal state of the transfer buffer.
~AudioTransferBuffer()
Destructor that deallocates the transfer buffer.
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
std::vector< uint8_t > bytes
Definition: sml_parser.h:12
size_t transfer_data_from_source(TickType_t ticks_to_wait)
Reads any available data from the sink into the transfer buffer.
virtual void clear_buffered_data()
Clears data in the transfer buffer and, if possible, the source/sink.
std::shared_ptr< RingBuffer > ring_buffer_