mirror of
https://github.com/esphome/esphome.git
synced 2026-05-09 21:28:40 +08:00
Use an RingBufferAudioSource in the SPDIF speaker
This commit is contained in:
@@ -143,7 +143,11 @@ void I2SAudioSpeakerSPDIF::run_speaker_task() {
|
||||
const uint32_t ring_buffer_duration = std::max(dma_buffers_duration_ms, this->buffer_duration_ms_);
|
||||
|
||||
// The DMA buffers may have more bits per sample, so calculate buffer sizes based on the input audio stream info
|
||||
const size_t ring_buffer_size = this->current_stream_info_.ms_to_bytes(ring_buffer_duration);
|
||||
const size_t bytes_per_frame = this->current_stream_info_.frames_to_bytes(1);
|
||||
// Round the ring buffer size down to a multiple of bytes_per_frame so the wrap boundary stays frame-aligned and
|
||||
// avoids unnecessary single-frame splices.
|
||||
const size_t ring_buffer_size =
|
||||
(this->current_stream_info_.ms_to_bytes(ring_buffer_duration) / bytes_per_frame) * bytes_per_frame;
|
||||
|
||||
// For SPDIF mode, one DMA buffer = one SPDIF block = 192 PCM frames
|
||||
const uint32_t frames_to_fill_single_dma_buffer = SPDIF_BLOCK_SAMPLES;
|
||||
@@ -151,13 +155,13 @@ void I2SAudioSpeakerSPDIF::run_speaker_task() {
|
||||
this->current_stream_info_.frames_to_bytes(frames_to_fill_single_dma_buffer);
|
||||
|
||||
bool successful_setup = false;
|
||||
std::unique_ptr<audio::AudioSourceTransferBuffer> transfer_buffer =
|
||||
audio::AudioSourceTransferBuffer::create(bytes_to_fill_single_dma_buffer);
|
||||
std::unique_ptr<audio::RingBufferAudioSource> audio_source;
|
||||
|
||||
if (transfer_buffer != nullptr) {
|
||||
{
|
||||
std::shared_ptr<ring_buffer::RingBuffer> temp_ring_buffer = ring_buffer::RingBuffer::create(ring_buffer_size);
|
||||
if (temp_ring_buffer.use_count() == 1) {
|
||||
transfer_buffer->set_source(temp_ring_buffer);
|
||||
audio_source = audio::RingBufferAudioSource::create(temp_ring_buffer, bytes_to_fill_single_dma_buffer,
|
||||
static_cast<uint8_t>(bytes_per_frame));
|
||||
if (audio_source != nullptr) {
|
||||
this->audio_ring_buffer_ = temp_ring_buffer;
|
||||
successful_setup = true;
|
||||
}
|
||||
@@ -297,24 +301,24 @@ void I2SAudioSpeakerSPDIF::run_speaker_task() {
|
||||
|
||||
if (!this->pause_state_) {
|
||||
while (real_frames_in_block < SPDIF_BLOCK_SAMPLES) {
|
||||
if (transfer_buffer->available() == 0) {
|
||||
size_t bytes_read = transfer_buffer->transfer_data_from_source(read_timeout_ticks);
|
||||
if (audio_source->available() == 0) {
|
||||
size_t bytes_read = audio_source->fill(read_timeout_ticks, false);
|
||||
if (bytes_read == 0) {
|
||||
break; // No upstream data within the read budget; silence-pad the remainder.
|
||||
}
|
||||
uint8_t *new_data = transfer_buffer->get_buffer_end() - bytes_read;
|
||||
uint8_t *new_data = audio_source->mutable_data();
|
||||
this->apply_software_volume_(new_data, bytes_read);
|
||||
this->swap_esp32_mono_samples_(new_data, bytes_read);
|
||||
}
|
||||
|
||||
const uint32_t frames_still_needed = SPDIF_BLOCK_SAMPLES - real_frames_in_block;
|
||||
const size_t bytes_still_needed = this->current_stream_info_.frames_to_bytes(frames_still_needed);
|
||||
const size_t bytes_to_feed = std::min(transfer_buffer->available(), bytes_still_needed);
|
||||
const size_t bytes_to_feed = std::min(audio_source->available(), bytes_still_needed);
|
||||
|
||||
uint32_t blocks_sent = 0;
|
||||
size_t pcm_consumed = 0;
|
||||
esp_err_t err = this->spdif_encoder_->write(transfer_buffer->get_buffer_start(), bytes_to_feed,
|
||||
write_timeout_ticks, &blocks_sent, &pcm_consumed);
|
||||
esp_err_t err = this->spdif_encoder_->write(audio_source->data(), bytes_to_feed, write_timeout_ticks,
|
||||
&blocks_sent, &pcm_consumed);
|
||||
if (err != ESP_OK) {
|
||||
// A failed (or timed-out) send leaves an unsent block in the encoder's stitch buffer;
|
||||
// resuming would credit the next iteration's bytes against an old block. Bail and
|
||||
@@ -325,7 +329,7 @@ void I2SAudioSpeakerSPDIF::run_speaker_task() {
|
||||
}
|
||||
|
||||
if (pcm_consumed > 0) {
|
||||
transfer_buffer->decrease_buffer_length(pcm_consumed);
|
||||
audio_source->consume(pcm_consumed);
|
||||
real_frames_in_block += this->current_stream_info_.bytes_to_frames(pcm_consumed);
|
||||
}
|
||||
if (blocks_sent > 0) {
|
||||
@@ -387,9 +391,7 @@ void I2SAudioSpeakerSPDIF::run_speaker_task() {
|
||||
this->spdif_encoder_->reset();
|
||||
}
|
||||
|
||||
if (transfer_buffer != nullptr) {
|
||||
transfer_buffer.reset();
|
||||
}
|
||||
audio_source.reset();
|
||||
|
||||
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::TASK_STOPPED);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user