summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-02-14 14:30:53 +1100
committerjacqueline <me@jacqueline.id.au>2023-02-14 14:30:53 +1100
commita65d996583c72e0d77805bcbc36da580aacb2848 (patch)
treeee64bb43ff2f44f495942e50e77176476b71f7b5 /src/audio
parentfa1f1cd9aba914882b95e93cdf64ad01309aa633 (diff)
downloadtangara-fw-a65d996583c72e0d77805bcbc36da580aacb2848.tar.gz
Use the sync apis for I2S output
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/audio_decoder.cpp9
-rw-r--r--src/audio/audio_task.cpp5
-rw-r--r--src/audio/fatfs_audio_input.cpp12
-rw-r--r--src/audio/i2s_audio_output.cpp96
-rw-r--r--src/audio/include/audio_task.hpp2
-rw-r--r--src/audio/include/i2s_audio_output.hpp4
6 files changed, 24 insertions, 104 deletions
diff --git a/src/audio/audio_decoder.cpp b/src/audio/audio_decoder.cpp
index d90ca496..97f45534 100644
--- a/src/audio/audio_decoder.cpp
+++ b/src/audio/audio_decoder.cpp
@@ -21,7 +21,7 @@ namespace audio {
static const char* kTag = "DEC";
-static const std::size_t kSamplesPerChunk = 256;
+static const std::size_t kSamplesPerChunk = 1024;
AudioDecoder::AudioDecoder()
: IAudioElement(),
@@ -89,14 +89,12 @@ auto AudioDecoder::ProcessEndOfStream() -> void {
needs_more_input_ = true;
current_codec_.reset();
- SendOrBufferEvent(
- std::unique_ptr<StreamEvent>(
- StreamEvent::CreateEndOfStream(input_events_)));
+ SendOrBufferEvent(std::unique_ptr<StreamEvent>(
+ StreamEvent::CreateEndOfStream(input_events_)));
}
auto AudioDecoder::Process() -> cpp::result<void, AudioProcessingError> {
if (has_samples_to_send_) {
- ESP_LOGI(kTag, "sending samples");
// Writing samples is relatively quick (it's just a bunch of memcopy's), so
// do them all at once.
while (has_samples_to_send_ && !IsOverBuffered()) {
@@ -132,7 +130,6 @@ auto AudioDecoder::Process() -> cpp::result<void, AudioProcessingError> {
}
if (!needs_more_input_) {
- ESP_LOGI(kTag, "decoding frame");
auto res = current_codec_->ProcessNextFrame();
if (res.has_error()) {
// todo
diff --git a/src/audio/audio_task.cpp b/src/audio/audio_task.cpp
index 078aa461..9d0c4bd0 100644
--- a/src/audio/audio_task.cpp
+++ b/src/audio/audio_task.cpp
@@ -38,8 +38,9 @@ auto StartAudioTask(const std::string& name,
ESP_LOGI(kTag, "starting audio task %s", name.c_str());
if (core_id) {
- xTaskCreatePinnedToCore(&AudioTaskMain, name.c_str(), element->StackSizeBytes(), args,
- kTaskPriorityAudio, task_handle.get(), *core_id);
+ xTaskCreatePinnedToCore(&AudioTaskMain, name.c_str(),
+ element->StackSizeBytes(), args, kTaskPriorityAudio,
+ task_handle.get(), *core_id);
} else {
xTaskCreate(&AudioTaskMain, name.c_str(), element->StackSizeBytes(), args,
kTaskPriorityAudio, task_handle.get());
diff --git a/src/audio/fatfs_audio_input.cpp b/src/audio/fatfs_audio_input.cpp
index 8990bf4f..fd1c1f3a 100644
--- a/src/audio/fatfs_audio_input.cpp
+++ b/src/audio/fatfs_audio_input.cpp
@@ -71,11 +71,10 @@ auto FatfsAudioInput::ProcessChunk(const cpp::span<std::byte>& chunk)
auto FatfsAudioInput::ProcessEndOfStream() -> void {
if (is_file_open_) {
- f_close(&current_file_);
- is_file_open_ = false;
- SendOrBufferEvent(
- std::unique_ptr<StreamEvent>(
- StreamEvent::CreateEndOfStream(input_events_)));
+ f_close(&current_file_);
+ is_file_open_ = false;
+ SendOrBufferEvent(std::unique_ptr<StreamEvent>(
+ StreamEvent::CreateEndOfStream(input_events_)));
}
}
@@ -85,7 +84,6 @@ auto FatfsAudioInput::Process() -> cpp::result<void, AudioProcessingError> {
StreamEvent::CreateChunkData(input_events_, kChunkSize));
UINT bytes_read = 0;
- ESP_LOGI(kTag, "reading from file");
FRESULT result = f_read(&current_file_, dest_event->chunk_data.raw_bytes,
kChunkSize, &bytes_read);
if (result != FR_OK) {
@@ -93,13 +91,11 @@ auto FatfsAudioInput::Process() -> cpp::result<void, AudioProcessingError> {
return cpp::fail(IO_ERROR);
}
- ESP_LOGI(kTag, "sending file data (%u bytes)", bytes_read);
dest_event->chunk_data.bytes =
dest_event->chunk_data.bytes.first(bytes_read);
SendOrBufferEvent(std::move(dest_event));
if (bytes_read < kChunkSize || f_eof(&current_file_)) {
- ESP_LOGI(kTag, "closing file");
f_close(&current_file_);
is_file_open_ = false;
}
diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp
index 3bed15b5..7ecadc03 100644
--- a/src/audio/i2s_audio_output.cpp
+++ b/src/audio/i2s_audio_output.cpp
@@ -43,22 +43,12 @@ I2SAudioOutput::I2SAudioOutput(drivers::GpioExpander* expander,
volume_(255),
is_soft_muted_(false),
chunk_reader_(),
- latest_chunk_(),
- dma_size_(),
- dma_queue_(nullptr) {}
+ latest_chunk_() {}
-I2SAudioOutput::~I2SAudioOutput() {
- if (dma_queue_ != nullptr) {
- ClearDmaQueue();
- }
- // TODO: power down the DAC.
-}
+I2SAudioOutput::~I2SAudioOutput() {}
auto I2SAudioOutput::HasUnprocessedInput() -> bool {
- if (dma_queue_ == nullptr || !dma_size_) {
- return false;
- }
- return latest_chunk_.size() >= *dma_size_;
+ return latest_chunk_.size() > 0;
}
auto I2SAudioOutput::ProcessStreamInfo(const StreamInfo& info)
@@ -108,77 +98,30 @@ auto I2SAudioOutput::ProcessStreamInfo(const StreamInfo& info)
return cpp::fail(UNSUPPORTED_STREAM);
}
- QueueHandle_t new_dma_queue =
- xQueueCreate(kDmaQueueLength, sizeof(std::byte*));
-
- dma_size_ = dac_->Reconfigure(bps, sample_rate, new_dma_queue);
-
- if (dma_queue_ != nullptr) {
- ClearDmaQueue();
- }
- dma_queue_ = new_dma_queue;
+ dac_->Reconfigure(bps, sample_rate);
return {};
}
auto I2SAudioOutput::ProcessChunk(const cpp::span<std::byte>& chunk)
-> cpp::result<std::size_t, AudioProcessingError> {
- ESP_LOGI(kTag, "received new samples");
latest_chunk_ = chunk_reader_->HandleNewData(chunk);
return 0;
}
auto I2SAudioOutput::ProcessEndOfStream() -> void {
- if (chunk_reader_ && dma_size_) {
- auto leftovers = chunk_reader_->GetLeftovers();
- if (leftovers.size() > 0 && leftovers.size() < *dma_size_) {
- std::byte* dest = static_cast<std::byte*>(malloc(*dma_size_));
- cpp::span dest_span(dest, *dma_size_);
-
- std::copy(leftovers.begin(), leftovers.end(), dest_span.begin());
- std::fill(dest_span.begin() + leftovers.size(), dest_span.end(), static_cast<std::byte>(0));
-
- xQueueSend(dma_queue_, &dest, portMAX_DELAY);
- }
- }
-
- SendOrBufferEvent(
- std::unique_ptr<StreamEvent>(
- StreamEvent::CreateEndOfStream(input_events_)));
-
- chunk_reader_.reset();
- dma_size_.reset();
+ SendOrBufferEvent(std::unique_ptr<StreamEvent>(
+ StreamEvent::CreateEndOfStream(input_events_)));
}
auto I2SAudioOutput::Process() -> cpp::result<void, AudioProcessingError> {
- std::size_t spaces_available = uxQueueSpacesAvailable(dma_queue_);
- if (spaces_available == 0) {
- // TODO: think about this more. can this just be the output event queue?
- vTaskDelay(pdMS_TO_TICKS(100));
- return {};
- }
-
- // Fill the queue as much as possible, since we need to be able to stream
- // FAST.
- while (latest_chunk_.size() >= *dma_size_ && spaces_available > 0) {
- // TODO: small memory arena for this?
- std::byte* dest = static_cast<std::byte*>(malloc(*dma_size_));
- cpp::span dest_span(dest, *dma_size_);
- cpp::span src_span = latest_chunk_.first(*dma_size_);
- std::copy(src_span.begin(), src_span.end(), dest_span.begin());
- if (!xQueueSend(dma_queue_, &dest, 0)) {
- // TODO: calculate how often we expect this to happen.
- free(dest);
- break;
- }
- latest_chunk_ = latest_chunk_.subspan(*dma_size_);
- ESP_LOGI(kTag, "wrote dma buffer of size %u", *dma_size_);
- }
- if (latest_chunk_.size() < *dma_size_) {
- // TODO: if this is the end of the stream, then we should be sending this
- // with zero padding. hmm. i guess we need an explicit EOF event?
- chunk_reader_->HandleBytesLeftOver(latest_chunk_.size());
- ESP_LOGI(kTag, "not enough samples for dma buffer");
+ // Note: no logging here!
+ std::size_t bytes_written = dac_->WriteData(latest_chunk_);
+ if (bytes_written == latest_chunk_.size_bytes()) {
+ latest_chunk_ = cpp::span<std::byte>();
+ chunk_reader_->HandleBytesLeftOver(0);
+ } else {
+ latest_chunk_ = latest_chunk_.subspan(bytes_written);
}
return {};
}
@@ -202,17 +145,4 @@ auto I2SAudioOutput::SetSoftMute(bool enabled) -> void {
}
}
-auto I2SAudioOutput::ClearDmaQueue() -> void {
- // Ensure we don't leak any memory from events leftover in the queue.
- while (uxQueueSpacesAvailable(dma_queue_) < kDmaQueueLength) {
- std::byte* data = nullptr;
- if (xQueueReceive(input_events_, &data, 0)) {
- free(data);
- } else {
- break;
- }
- }
- vQueueDelete(dma_queue_);
-}
-
} // namespace audio
diff --git a/src/audio/include/audio_task.hpp b/src/audio/include/audio_task.hpp
index 399ad679..0b353735 100644
--- a/src/audio/include/audio_task.hpp
+++ b/src/audio/include/audio_task.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <memory>
-#include <string>
#include <optional>
+#include <string>
#include "audio_element.hpp"
#include "audio_element_handle.hpp"
diff --git a/src/audio/include/i2s_audio_output.hpp b/src/audio/include/i2s_audio_output.hpp
index b4fd4c59..fc406665 100644
--- a/src/audio/include/i2s_audio_output.hpp
+++ b/src/audio/include/i2s_audio_output.hpp
@@ -38,8 +38,6 @@ class I2SAudioOutput : public IAudioElement {
auto SetVolume(uint8_t volume) -> void;
auto SetSoftMute(bool enabled) -> void;
- auto ClearDmaQueue() -> void;
-
drivers::GpioExpander* expander_;
std::unique_ptr<drivers::AudioDac> dac_;
@@ -48,8 +46,6 @@ class I2SAudioOutput : public IAudioElement {
std::optional<ChunkReader> chunk_reader_;
cpp::span<std::byte> latest_chunk_;
- std::optional<std::size_t> dma_size_;
- QueueHandle_t dma_queue_;
};
} // namespace audio