Ensure the sink buffer is large enough to not fully drain during

playback
custom
jacqueline 2 years ago
parent 25c5896dc5
commit 561f9d2a07
  1. 2
      src/audio/CMakeLists.txt
  2. 7
      src/audio/audio_decoder.cpp
  3. 7
      src/audio/audio_task.cpp
  4. 3
      src/audio/fatfs_audio_input.cpp
  5. 3
      src/audio/include/audio_sink.hpp
  6. 52
      src/audio/include/stream_info.hpp
  7. 10
      src/drivers/dac.cpp

@ -1,7 +1,7 @@
idf_component_register(
SRCS "audio_decoder.cpp" "audio_task.cpp" "chunk.cpp" "fatfs_audio_input.cpp"
"stream_message.cpp" "i2s_audio_output.cpp" "stream_buffer.cpp"
"audio_playback.cpp" "stream_event.cpp" "pipeline.cpp"
"audio_playback.cpp" "stream_event.cpp" "pipeline.cpp" "stream_info.cpp"
INCLUDE_DIRS "include"
REQUIRES "codecs" "drivers" "cbor" "result" "tasks" "span" "memory")

@ -68,8 +68,10 @@ auto AudioDecoder::Process(const std::vector<InputStream>& inputs,
OutputStream* output) -> void {
auto input = inputs.begin();
const StreamInfo& info = input->info();
if (std::holds_alternative<std::monostate>(info.format) || info.bytes_in_stream == 0) {
output->prepare({});
if (std::holds_alternative<std::monostate>(info.format) ||
info.bytes_in_stream == 0) {
// TODO(jacqueline): should we clear the stream format?
// output->prepare({});
return;
}
@ -126,7 +128,6 @@ auto AudioDecoder::Process(const std::vector<InputStream>& inputs,
}
}
ESP_LOGI(kTag, "decoded %u bytes", current_codec_->GetInputPosition() - 1);
input->consume(current_codec_->GetInputPosition() - 1);
}

@ -124,7 +124,7 @@ void AudioTaskMain(void* args) {
RawStream raw_sink_stream = elements.front()->OutStream(&out_region);
InputStream sink_stream(&raw_sink_stream);
if (sink_stream.data().size_bytes() == 0) {
if (sink_stream.info().bytes_in_stream == 0) {
out_region.Unmap();
vTaskDelay(pdMS_TO_TICKS(100));
continue;
@ -143,7 +143,8 @@ void AudioTaskMain(void* args) {
// We've reconfigured the sink, or it was already configured correctly.
// Send through some data.
if (output_format == sink_stream.info().format && !std::holds_alternative<std::monostate>(*output_format)) {
if (output_format == sink_stream.info().format &&
!std::holds_alternative<std::monostate>(*output_format)) {
// TODO: tune the delay on this, as it's currently the only way to
// throttle this task's CPU time. Maybe also hold off on the pipeline
// if the buffer is already close to full?
@ -160,7 +161,7 @@ void AudioTaskMain(void* args) {
vTaskDelete(NULL);
}
static std::byte sDrainBuf[1024];
static std::byte sDrainBuf[8 * 1024];
void AudioDrainMain(void* args) {
{

@ -48,7 +48,8 @@ auto FatfsAudioInput::OpenFile(const std::string& path) -> void {
auto FatfsAudioInput::Process(const std::vector<InputStream>& inputs,
OutputStream* output) -> void {
if (!is_file_open_) {
output->prepare({});
// TODO(jacqueline): should we clear the stream format?
// output->prepare({});
return;
}

@ -6,7 +6,8 @@ namespace audio {
class IAudioSink {
private:
static const std::size_t kDrainBufferSize = 8 * 1024;
// TODO: tune. at least about 12KiB seems right for mp3
static const std::size_t kDrainBufferSize = 24 * 1024;
StreamBufferHandle_t buffer_;
public:

@ -66,20 +66,13 @@ class InputStream {
public:
explicit InputStream(RawStream* s) : raw_(s) {}
void 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 consume(std::size_t bytes) const;
void mark_incomplete() const { raw_->is_incomplete = true; }
void mark_incomplete() const;
const StreamInfo& info() const { return *raw_->info; }
const StreamInfo& info() const;
cpp::span<const std::byte> data() const {
return raw_->data.first(raw_->info->bytes_in_stream);
}
cpp::span<const std::byte> data() const;
private:
RawStream* raw_;
@ -89,34 +82,15 @@ class OutputStream {
public:
explicit OutputStream(RawStream* s) : raw_(s) {}
void add(std::size_t bytes) const {
assert(raw_->info->bytes_in_stream + bytes <= raw_->data.size_bytes());
raw_->info->bytes_in_stream += bytes;
}
bool 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;
}
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& info() const { return *raw_->info; }
cpp::span<std::byte> data() const {
return raw_->data.subspan(raw_->info->bytes_in_stream);
}
bool is_incomplete() const { return raw_->is_incomplete; }
void add(std::size_t bytes) const;
bool prepare(const StreamInfo::Format& new_format);
const StreamInfo& info() const;
cpp::span<std::byte> data() const;
bool is_incomplete() const;
private:
RawStream* raw_;

@ -91,11 +91,11 @@ auto AudioDac::create(GpioExpander* expander)
// dac->WriteRegister(Register::PLL_CLOCK_SOURCE, 1 << 4);
// dac->WriteRegister(Register::DAC_CLOCK_SOURCE, 0b11 << 5);
//dac->WriteRegister(Register::PLL_ENABLE, 0);
//dac->WriteRegister(Register::DAC_CLOCK_SOURCE, 0b0110000);
//dac->WriteRegister(Register::CLOCK_ERRORS, 0b01000001);
//dac->WriteRegister(Register::I2S_FORMAT, 0b110000);
// dac->WriteRegister(Register::INTERPOLATION, 1 << 4);
// dac->WriteRegister(Register::PLL_ENABLE, 0);
// dac->WriteRegister(Register::DAC_CLOCK_SOURCE, 0b0110000);
// dac->WriteRegister(Register::CLOCK_ERRORS, 0b01000001);
// dac->WriteRegister(Register::I2S_FORMAT, 0b110000);
// dac->WriteRegister(Register::INTERPOLATION, 1 << 4);
dac->Reconfigure(BPS_16, SAMPLE_RATE_44_1);

Loading…
Cancel
Save