summaryrefslogtreecommitdiff
path: root/src/audio/audio_task.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-08-03 15:32:28 +1000
committerjacqueline <me@jacqueline.id.au>2023-08-03 15:32:28 +1000
commit3511852f39cd5023ec8e6d0b94cc69f34e9201ed (patch)
treefa38c2dd0a88d39616540e59f9850b919e20d852 /src/audio/audio_task.cpp
parentfbebc525117f18d5751e6951bc4ffcc51f70dcc4 (diff)
downloadtangara-fw-3511852f39cd5023ec8e6d0b94cc69f34e9201ed.tar.gz
Add very limited resampling (it's slow as shit)
Diffstat (limited to 'src/audio/audio_task.cpp')
-rw-r--r--src/audio/audio_task.cpp81
1 files changed, 53 insertions, 28 deletions
diff --git a/src/audio/audio_task.cpp b/src/audio/audio_task.cpp
index 7e0fb207..c3498965 100644
--- a/src/audio/audio_task.cpp
+++ b/src/audio/audio_task.cpp
@@ -34,6 +34,7 @@
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "pipeline.hpp"
+#include "sink_mixer.hpp"
#include "span.hpp"
#include "arena.hpp"
@@ -115,14 +116,12 @@ AudioTask::AudioTask(IAudioSource* source, IAudioSink* sink)
: source_(source),
sink_(sink),
codec_(),
+ mixer_(new SinkMixer(sink->stream())),
timer_(),
has_begun_decoding_(false),
current_input_format_(),
current_output_format_(),
- sample_buffer_(reinterpret_cast<std::byte*>(
- heap_caps_malloc(kSampleBufferSize,
- MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))),
- sample_buffer_len_(kSampleBufferSize) {}
+ codec_buffer_(new RawStream(kSampleBufferSize)) {}
void AudioTask::Main() {
for (;;) {
@@ -246,13 +245,17 @@ auto AudioTask::BeginDecoding(InputStream& stream) -> bool {
return false;
}
+ OutputStream writer{codec_buffer_.get()};
+ writer.prepare(new_format, {});
+
return true;
}
auto AudioTask::ContinueDecoding(InputStream& stream) -> bool {
while (!stream.data().empty()) {
- auto res = codec_->ContinueStream(stream.data(),
- {sample_buffer_, sample_buffer_len_});
+ OutputStream writer{codec_buffer_.get()};
+
+ auto res = codec_->ContinueStream(stream.data(), writer.data());
stream.consume(res.first);
@@ -263,9 +266,10 @@ auto AudioTask::ContinueDecoding(InputStream& stream) -> bool {
return false;
}
} else {
- xStreamBufferSend(sink_->stream(), sample_buffer_,
- res.second->bytes_written, portMAX_DELAY);
- timer_->AddBytes(res.second->bytes_written);
+ writer.add(res.second->bytes_written);
+
+ InputStream reader{codec_buffer_.get()};
+ SendToSink(reader);
}
}
return true;
@@ -284,21 +288,22 @@ auto AudioTask::FinishDecoding(InputStream& stream) -> void {
std::unique_ptr<RawStream> mad_buffer;
mad_buffer.reset(new RawStream(stream.data().size_bytes() + 8));
- OutputStream writer{mad_buffer.get()};
+ OutputStream mad_writer{mad_buffer.get()};
std::copy(stream.data().begin(), stream.data().end(),
- writer.data().begin());
- std::fill(writer.data().begin(), writer.data().end(), std::byte{0});
+ mad_writer.data().begin());
+ std::fill(mad_writer.data().begin(), mad_writer.data().end(), std::byte{0});
InputStream padded_stream{mad_buffer.get()};
- auto res = codec_->ContinueStream(stream.data(),
- {sample_buffer_, sample_buffer_len_});
+ OutputStream writer{codec_buffer_.get()};
+ auto res = codec_->ContinueStream(stream.data(), writer.data());
if (res.second.has_error()) {
return;
}
- xStreamBufferSend(sink_->stream(), sample_buffer_,
- res.second->bytes_written, portMAX_DELAY);
- timer_->AddBytes(res.second->bytes_written);
+ writer.add(res.second->bytes_written);
+
+ InputStream reader{codec_buffer_.get()};
+ SendToSink(reader);
}
}
@@ -319,24 +324,31 @@ auto AudioTask::ForwardPcmStream(StreamInfo::Pcm& format,
xStreamBufferSend(sink_->stream(), samples.data(), samples.size_bytes(),
portMAX_DELAY);
timer_->AddBytes(samples.size_bytes());
+ InputStream reader{codec_buffer_.get()};
+ SendToSink(reader);
+
return true;
}
auto AudioTask::ConfigureSink(const StreamInfo::Pcm& format,
const Duration& duration) -> bool {
if (format != current_output_format_) {
- // The new format is different to the old one. Wait for the sink to drain
- // before continuing.
- while (!xStreamBufferIsEmpty(sink_->stream())) {
- ESP_LOGI(kTag, "waiting for sink stream to drain...");
- // TODO(jacqueline): Get the sink drain ISR to notify us of this
- // via semaphore instead of busy-ish waiting.
- vTaskDelay(pdMS_TO_TICKS(100));
- }
+ current_output_format_ = format;
+ StreamInfo::Pcm new_sink_format = sink_->PrepareFormat(format);
+ if (new_sink_format != current_sink_format_) {
+ current_sink_format_ = new_sink_format;
+
+ // The new format is different to the old one. Wait for the sink to drain
+ // before continuing.
+ while (!xStreamBufferIsEmpty(sink_->stream())) {
+ ESP_LOGI(kTag, "waiting for sink stream to drain...");
+ // TODO(jacqueline): Get the sink drain ISR to notify us of this
+ // via semaphore instead of busy-ish waiting.
+ vTaskDelay(pdMS_TO_TICKS(10));
+ }
- ESP_LOGI(kTag, "configuring sink");
- if (!sink_->Configure(format)) {
- return false;
+ ESP_LOGI(kTag, "configuring sink");
+ sink_->Configure(new_sink_format);
}
}
@@ -345,4 +357,17 @@ auto AudioTask::ConfigureSink(const StreamInfo::Pcm& format,
return true;
}
+auto AudioTask::SendToSink(InputStream& stream) -> void {
+ std::size_t bytes_to_send = stream.data().size_bytes();
+ std::size_t bytes_sent;
+ if (stream.info().format_as<StreamInfo::Pcm>() == current_sink_format_) {
+ bytes_sent = xStreamBufferSend(sink_->stream(), stream.data().data(),
+ bytes_to_send, portMAX_DELAY);
+ stream.consume(bytes_sent);
+ } else {
+ bytes_sent = mixer_->MixAndSend(stream, current_sink_format_.value());
+ }
+ timer_->AddBytes(bytes_sent);
+}
+
} // namespace audio