diff --git a/esphome/components/audio/audio_transfer_buffer.cpp b/esphome/components/audio/audio_transfer_buffer.cpp index 790cd62db0..ddb669e0eb 100644 --- a/esphome/components/audio/audio_transfer_buffer.cpp +++ b/esphome/components/audio/audio_transfer_buffer.cpp @@ -2,6 +2,8 @@ #ifdef USE_ESP32 +#include + #include "esphome/core/helpers.h" namespace esphome { @@ -75,12 +77,32 @@ bool AudioTransferBuffer::has_buffered_data() const { } bool AudioTransferBuffer::reallocate(size_t new_buffer_size) { - if (this->buffer_length_ > 0) { - // Buffer currently has data, so reallocation is impossible + if (this->buffer_ == nullptr) { + return this->allocate_buffer_(new_buffer_size); + } + + if (new_buffer_size < this->buffer_length_) { + // New size is too small to hold existing data return false; } - this->deallocate_buffer_(); - return this->allocate_buffer_(new_buffer_size); + + // Shift existing data to the start of the buffer so realloc preserves it + if ((this->buffer_length_ > 0) && (this->data_start_ != this->buffer_)) { + std::memmove(this->buffer_, this->data_start_, this->buffer_length_); + this->data_start_ = this->buffer_; + } + + RAMAllocator allocator; + uint8_t *new_buffer = allocator.reallocate(this->buffer_, new_buffer_size); + if (new_buffer == nullptr) { + // Reallocation failed, but the original buffer is still valid + return false; + } + + this->buffer_ = new_buffer; + this->data_start_ = this->buffer_; + this->buffer_size_ = new_buffer_size; + return true; } bool AudioTransferBuffer::allocate_buffer_(size_t buffer_size) { @@ -115,7 +137,7 @@ size_t AudioSourceTransferBuffer::transfer_data_from_source(TickType_t ticks_to_ if (pre_shift) { // Shift data in buffer to start if (this->buffer_length_ > 0) { - memmove(this->buffer_, this->data_start_, this->buffer_length_); + std::memmove(this->buffer_, this->data_start_, this->buffer_length_); } this->data_start_ = this->buffer_; } @@ -150,7 +172,7 @@ size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait, if (post_shift) { // Shift unwritten data to the start of the buffer - memmove(this->buffer_, this->data_start_, this->buffer_length_); + std::memmove(this->buffer_, this->data_start_, this->buffer_length_); this->data_start_ = this->buffer_; } diff --git a/esphome/components/audio/audio_transfer_buffer.h b/esphome/components/audio/audio_transfer_buffer.h index edb484e7d2..24c0670d1a 100644 --- a/esphome/components/audio/audio_transfer_buffer.h +++ b/esphome/components/audio/audio_transfer_buffer.h @@ -56,6 +56,9 @@ class AudioTransferBuffer { /// @return True if there is data, false otherwise. virtual bool has_buffered_data() const; + /// @brief Reallocates the transfer buffer, preserving any existing data. + /// @param new_buffer_size The new size in bytes. Must be at least as large as available(). + /// @return True if successful, false otherwise. On failure, the original buffer remains valid. bool reallocate(size_t new_buffer_size); protected: