diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-09-09 15:15:00 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-09-09 15:15:00 +1000 |
| commit | 2b1a01705d62d08cefd6816ba108c5cae48a50ac (patch) | |
| tree | 20ba16a6259ffc335dbcded84fa6bcbe327e9d84 /src/tangara/audio/audio_decoder.cpp | |
| parent | 9475d10d1000c7e21a7ea311b0c8ee6a72ef46c4 (diff) | |
| parent | acdc9789c90ed6f083d054cd07930e020123457f (diff) | |
| download | tangara-fw-2b1a01705d62d08cefd6816ba108c5cae48a50ac.tar.gz | |
Merge branch 'main' into jqln/tts
Diffstat (limited to 'src/tangara/audio/audio_decoder.cpp')
| -rw-r--r-- | src/tangara/audio/audio_decoder.cpp | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/src/tangara/audio/audio_decoder.cpp b/src/tangara/audio/audio_decoder.cpp index ee06d984..8c0b264f 100644 --- a/src/tangara/audio/audio_decoder.cpp +++ b/src/tangara/audio/audio_decoder.cpp @@ -48,7 +48,7 @@ static const char* kTag = "decoder"; * increasing its size. */ static constexpr std::size_t kCodecBufferLength = - drivers::kI2SBufferLengthFrames * sizeof(sample::Sample); + drivers::kI2SBufferLengthFrames * 2; auto Decoder::Start(std::shared_ptr<SampleProcessor> sink) -> Decoder* { Decoder* task = new Decoder(sink); @@ -78,11 +78,17 @@ Decoder::Decoder(std::shared_ptr<SampleProcessor> processor) * Main decoding loop. Handles watching for new streams, or continuing to nudge * along the current stream if we have one. */ +IRAM_ATTR void Decoder::Main() { for (;;) { - // Check whether there's a new stream to begin. If we're idle, then we - // simply park and wait forever for a stream to arrive. - TickType_t wait_time = stream_ ? 0 : portMAX_DELAY; + // How long should we spend waiting for a command? By default, assume we're + // idle and wait forever. + TickType_t wait_time = portMAX_DELAY; + if (!leftover_samples_.empty() || stream_) { + // If we have work to do, then don't block waiting for a new stream. + wait_time = 0; + } + NextStream* next; if (xQueueReceive(next_stream_, &next, wait_time)) { // Copy the data out of the queue, then clean up the item. @@ -103,8 +109,15 @@ void Decoder::Main() { // Start decoding the new stream. prepareDecode(new_stream); + + // Keep handling commands until the command queue is empty. + continue; } + // We should always have a stream if we returned from xQueueReceive without + // receiving a new stream. + assert(stream_); + if (!continueDecode()) { finishDecode(false); } @@ -167,16 +180,36 @@ auto Decoder::prepareDecode(std::shared_ptr<TaggedStream> stream) -> void { } auto Decoder::continueDecode() -> bool { + // First, see if we have any samples from a previous decode that still need + // to be sent. + if (!leftover_samples_.empty()) { + leftover_samples_ = processor_->continueStream(leftover_samples_); + return true; + } + + // We might have already cleaned up the codec if the last decode pass of the + // stream resulted in leftover samples. + if (!codec_) { + return false; + } + auto res = codec_->DecodeTo(codec_buffer_); if (res.has_error()) { return false; } if (res->samples_written > 0) { - processor_->continueStream(codec_buffer_.first(res->samples_written)); + leftover_samples_ = + processor_->continueStream(codec_buffer_.first(res->samples_written)); + } + + if (res->is_stream_finished) { + // The codec has finished, so make sure we don't call it again. + codec_.reset(); } - return !res->is_stream_finished; + // We're done iff the codec has finished and we sent everything. + return codec_ || !leftover_samples_.empty(); } auto Decoder::finishDecode(bool cancel) -> void { @@ -191,6 +224,7 @@ auto Decoder::finishDecode(bool cancel) -> void { processor_->endStream(cancel); // Clean up after ourselves. + leftover_samples_ = {}; stream_.reset(); codec_.reset(); track_.reset(); |
