[mixer] Fix memory leak in mixer task on stop/start cycles (#15185)

This commit is contained in:
Kevin Ahrendt
2026-03-31 19:06:48 -04:00
committed by Jesse Hills
parent dc634b8c7b
commit 514c0c8331
@@ -597,6 +597,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
xEventGroupSetBits(this_mixer->event_group_, MIXER_TASK_STATE_STARTING); xEventGroupSetBits(this_mixer->event_group_, MIXER_TASK_STATE_STARTING);
{ // Ensure C++ objects fall out of scope to ensure proper cleanup before stopping the task
std::unique_ptr<audio::AudioSinkTransferBuffer> output_transfer_buffer = audio::AudioSinkTransferBuffer::create( std::unique_ptr<audio::AudioSinkTransferBuffer> output_transfer_buffer = audio::AudioSinkTransferBuffer::create(
this_mixer->audio_stream_info_.value().ms_to_bytes(TRANSFER_BUFFER_DURATION_MS)); this_mixer->audio_stream_info_.value().ms_to_bytes(TRANSFER_BUFFER_DURATION_MS));
@@ -671,8 +672,8 @@ void MixerSpeaker::audio_mixer_task(void *params) {
const uint32_t frames_available_in_buffer = const uint32_t frames_available_in_buffer =
active_stream_info.bytes_to_frames(transfer_buffers_with_data[0]->available()); active_stream_info.bytes_to_frames(transfer_buffers_with_data[0]->available());
frames_to_mix = std::min(frames_to_mix, frames_available_in_buffer); frames_to_mix = std::min(frames_to_mix, frames_available_in_buffer);
copy_frames(reinterpret_cast<int16_t *>(transfer_buffers_with_data[0]->get_buffer_start()), active_stream_info, copy_frames(reinterpret_cast<int16_t *>(transfer_buffers_with_data[0]->get_buffer_start()),
reinterpret_cast<int16_t *>(output_transfer_buffer->get_buffer_end()), active_stream_info, reinterpret_cast<int16_t *>(output_transfer_buffer->get_buffer_end()),
this_mixer->audio_stream_info_.value(), frames_to_mix); this_mixer->audio_stream_info_.value(), frames_to_mix);
// Set playback delay for newly contributing source // Set playback delay for newly contributing source
@@ -712,8 +713,8 @@ void MixerSpeaker::audio_mixer_task(void *params) {
} else { } else {
// Determine how many frames to mix // Determine how many frames to mix
for (size_t i = 0; i < transfer_buffers_with_data.size(); ++i) { for (size_t i = 0; i < transfer_buffers_with_data.size(); ++i) {
const uint32_t frames_available_in_buffer = const uint32_t frames_available_in_buffer = speakers_with_data[i]->get_audio_stream_info().bytes_to_frames(
speakers_with_data[i]->get_audio_stream_info().bytes_to_frames(transfer_buffers_with_data[i]->available()); transfer_buffers_with_data[i]->available());
frames_to_mix = std::min(frames_to_mix, frames_available_in_buffer); frames_to_mix = std::min(frames_to_mix, frames_available_in_buffer);
} }
int16_t *primary_buffer = reinterpret_cast<int16_t *>(transfer_buffers_with_data[0]->get_buffer_start()); int16_t *primary_buffer = reinterpret_cast<int16_t *>(transfer_buffers_with_data[0]->get_buffer_start());
@@ -758,12 +759,11 @@ void MixerSpeaker::audio_mixer_task(void *params) {
} }
xEventGroupSetBits(this_mixer->event_group_, MIXER_TASK_STATE_STOPPING); xEventGroupSetBits(this_mixer->event_group_, MIXER_TASK_STATE_STOPPING);
}
// Reset pipeline frame count since the task is stopping // Reset pipeline frame count since the task is stopping
this_mixer->frames_in_pipeline_.store(0, std::memory_order_release); this_mixer->frames_in_pipeline_.store(0, std::memory_order_release);
output_transfer_buffer.reset();
xEventGroupSetBits(this_mixer->event_group_, MIXER_TASK_STATE_STOPPED); xEventGroupSetBits(this_mixer->event_group_, MIXER_TASK_STATE_STOPPED);
vTaskSuspend(nullptr); // Suspend this task indefinitely until the loop method deletes it vTaskSuspend(nullptr); // Suspend this task indefinitely until the loop method deletes it