summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-04-19 16:45:50 +1000
committerjacqueline <me@jacqueline.id.au>2023-04-19 16:45:50 +1000
commit4c77950e702a329f3136456a932efbea36e03d42 (patch)
tree5df7e8717b751846655c16b50c352712b642658b /src/audio
parent561f9d2a07ee6ee1c2f18dc375125f87ea7b0d55 (diff)
downloadtangara-fw-4c77950e702a329f3136456a932efbea36e03d42.tar.gz
Pipeline working and outputting correctly, but noisy
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/audio_decoder.cpp5
-rw-r--r--src/audio/audio_task.cpp12
-rw-r--r--src/audio/i2s_audio_output.cpp8
-rw-r--r--src/audio/include/audio_sink.hpp24
-rw-r--r--src/audio/stream_info.cpp70
5 files changed, 106 insertions, 13 deletions
diff --git a/src/audio/audio_decoder.cpp b/src/audio/audio_decoder.cpp
index af9abb94..4b9826a9 100644
--- a/src/audio/audio_decoder.cpp
+++ b/src/audio/audio_decoder.cpp
@@ -128,7 +128,10 @@ auto AudioDecoder::Process(const std::vector<InputStream>& inputs,
}
}
- input->consume(current_codec_->GetInputPosition() - 1);
+ std::size_t pos = current_codec_->GetInputPosition();
+ if (pos > 0) {
+ input->consume(pos - 1);
+ }
}
} // namespace audio
diff --git a/src/audio/audio_task.cpp b/src/audio/audio_task.cpp
index 3a2a5941..1670f9f6 100644
--- a/src/audio/audio_task.cpp
+++ b/src/audio/audio_task.cpp
@@ -45,7 +45,7 @@ auto StartPipeline(Pipeline* pipeline, IAudioSink* sink) -> void {
ESP_LOGI(kTag, "starting audio pipeline task");
xTaskCreatePinnedToCore(&AudioTaskMain, "pipeline", kStackSize, args,
- kTaskPriorityAudio, NULL, kAudioCore);
+ kTaskPriorityAudioPipeline, NULL, kAudioCore);
}
auto StartDrain(IAudioSink* sink) -> void {
@@ -57,8 +57,8 @@ auto StartDrain(IAudioSink* sink) -> void {
};
ESP_LOGI(kTag, "starting audio drain task");
- xTaskCreatePinnedToCore(&AudioDrainMain, "drain", kDrainStackSize, drain_args,
- kTaskPriorityAudio, NULL, kAudioCore);
+ xTaskCreate(&AudioDrainMain, "drain", kDrainStackSize, drain_args,
+ kTaskPriorityAudioDrain, NULL);
}
void AudioTaskMain(void* args) {
@@ -134,7 +134,7 @@ void AudioTaskMain(void* args) {
// The format of the stream within the sink stream has changed. We
// need to reconfigure the sink, but shouldn't do so until we've fully
// drained the current buffer.
- if (xStreamBufferIsEmpty(sink->buffer())) {
+ if (xStreamBufferIsEmpty(*sink->buffer())) {
ESP_LOGI(kTag, "reconfiguring dac");
output_format = sink_stream.info().format;
sink->Configure(*output_format);
@@ -149,7 +149,7 @@ void AudioTaskMain(void* args) {
// throttle this task's CPU time. Maybe also hold off on the pipeline
// if the buffer is already close to full?
std::size_t sent = xStreamBufferSend(
- sink->buffer(), sink_stream.data().data(),
+ *sink->buffer(), sink_stream.data().data(),
sink_stream.data().size_bytes(), pdMS_TO_TICKS(10));
sink_stream.consume(sent);
}
@@ -172,7 +172,7 @@ void AudioDrainMain(void* args) {
// TODO(jacqueline): implement PAUSE without busy-waiting.
while (*command != QUIT) {
- std::size_t len = xStreamBufferReceive(sink->buffer(), sDrainBuf,
+ std::size_t len = xStreamBufferReceive(*sink->buffer(), sDrainBuf,
sizeof(sDrainBuf), portMAX_DELAY);
if (len > 0) {
sink->Send({sDrainBuf, len});
diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp
index 2d336152..7e9e9353 100644
--- a/src/audio/i2s_audio_output.cpp
+++ b/src/audio/i2s_audio_output.cpp
@@ -38,9 +38,13 @@ auto I2SAudioOutput::create(drivers::GpioExpander* expander)
I2SAudioOutput::I2SAudioOutput(drivers::GpioExpander* expander,
std::unique_ptr<drivers::AudioDac> dac)
- : expander_(expander), dac_(std::move(dac)), current_config_() {}
+ : expander_(expander), dac_(std::move(dac)), current_config_() {
+ //dac_->SetSource(buffer());
+ }
-I2SAudioOutput::~I2SAudioOutput() {}
+I2SAudioOutput::~I2SAudioOutput() {
+ dac_->SetSource(nullptr);
+}
auto I2SAudioOutput::Configure(const StreamInfo::Format& format) -> bool {
if (!std::holds_alternative<StreamInfo::Pcm>(format)) {
diff --git a/src/audio/include/audio_sink.hpp b/src/audio/include/audio_sink.hpp
index 03a4690d..a11a9c92 100644
--- a/src/audio/include/audio_sink.hpp
+++ b/src/audio/include/audio_sink.hpp
@@ -1,6 +1,9 @@
#pragma once
+#include <stdint.h>
#include "audio_element.hpp"
+#include "esp_heap_caps.h"
+#include "freertos/FreeRTOS.h"
#include "stream_info.hpp"
namespace audio {
@@ -8,17 +11,30 @@ class IAudioSink {
private:
// TODO: tune. at least about 12KiB seems right for mp3
static const std::size_t kDrainBufferSize = 24 * 1024;
- StreamBufferHandle_t buffer_;
+ uint8_t *buffer_;
+ StaticStreamBuffer_t *metadata_;
+ StreamBufferHandle_t *handle_;
public:
- IAudioSink() : buffer_(xStreamBufferCreate(kDrainBufferSize, 1)) {}
- virtual ~IAudioSink() { vStreamBufferDelete(buffer_); }
+ IAudioSink() :
+ buffer_(reinterpret_cast<uint8_t*>(heap_caps_malloc(kDrainBufferSize, MALLOC_CAP_DMA))),
+ metadata_(reinterpret_cast<StaticStreamBuffer_t*>(heap_caps_malloc(sizeof(StaticStreamBuffer_t), MALLOC_CAP_DMA))),
+ handle_(reinterpret_cast<StreamBufferHandle_t*>(heap_caps_malloc(sizeof(StreamBufferHandle_t), MALLOC_CAP_DMA))) {
+ *handle_ = xStreamBufferCreateStatic(kDrainBufferSize, 1, buffer_, metadata_);
+ }
+
+ virtual ~IAudioSink() {
+ vStreamBufferDelete(*handle_);
+ free(buffer_);
+ free(handle_);
+ free(metadata_);
+ }
virtual auto Configure(const StreamInfo::Format& format) -> bool = 0;
virtual auto Send(const cpp::span<std::byte>& data) -> void = 0;
virtual auto Log() -> void {}
- auto buffer() const -> StreamBufferHandle_t { return buffer_; }
+ auto buffer() -> StreamBufferHandle_t* { return handle_; }
};
} // namespace audio
diff --git a/src/audio/stream_info.cpp b/src/audio/stream_info.cpp
new file mode 100644
index 00000000..7d833d25
--- /dev/null
+++ b/src/audio/stream_info.cpp
@@ -0,0 +1,70 @@
+#include "stream_info.hpp"
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+#include "result.hpp"
+#include "span.hpp"
+#include "types.hpp"
+
+namespace audio {
+
+void InputStream::consume(std::size_t bytes) const {
+ assert(raw_->info->bytes_in_stream >= bytes);
+ auto new_data = raw_->data.subspan(bytes);
+ std::move(new_data.begin(), new_data.end(), raw_->data.begin());
+ raw_->info->bytes_in_stream = new_data.size_bytes();
+}
+
+void InputStream::mark_incomplete() const {
+ raw_->is_incomplete = true;
+}
+
+const StreamInfo& InputStream::info() const {
+ return *raw_->info;
+}
+
+cpp::span<const std::byte> InputStream::data() const {
+ return raw_->data.first(raw_->info->bytes_in_stream);
+}
+
+void OutputStream::add(std::size_t bytes) const {
+ assert(raw_->info->bytes_in_stream + bytes <= raw_->data.size_bytes());
+ raw_->info->bytes_in_stream += bytes;
+}
+
+bool OutputStream::prepare(const StreamInfo::Format& new_format) {
+ if (std::holds_alternative<std::monostate>(raw_->info->format)) {
+ raw_->info->format = new_format;
+ raw_->info->bytes_in_stream = 0;
+ return true;
+ }
+ if (new_format == raw_->info->format) {
+ return true;
+ }
+ if (raw_->is_incomplete) {
+ raw_->info->format = new_format;
+ raw_->info->bytes_in_stream = 0;
+ return true;
+ }
+ return false;
+}
+
+const StreamInfo& OutputStream::info() const {
+ return *raw_->info;
+}
+
+cpp::span<std::byte> OutputStream::data() const {
+ return raw_->data.subspan(raw_->info->bytes_in_stream);
+}
+
+bool OutputStream::is_incomplete() const {
+ return raw_->is_incomplete;
+}
+
+} // namespace audio