/* * Copyright 2023 jacqueline * * SPDX-License-Identifier: GPL-3.0-only */ #include "foxenflac.hpp" #include #include #include #include "esp_log.h" #include "foxen/flac.h" #include "sample.hpp" namespace codecs { [[maybe_unused]] static const char kTag[] = "flac"; FoxenFlacDecoder::FoxenFlacDecoder() : input_(), buffer_(), flac_(fx_flac_init( heap_caps_malloc(fx_flac_size(FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, 2), MALLOC_CAP_SPIRAM), FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, 2)) {} FoxenFlacDecoder::~FoxenFlacDecoder() { free(flac_); } auto FoxenFlacDecoder::OpenStream(std::shared_ptr input) -> cpp::result { input_ = input; bool eof = false; fx_flac_state_t state; do { eof = buffer_.Refill(input_.get()); buffer_.ConsumeBytes([&](cpp::span buf) -> size_t { uint32_t bytes_used = buf.size(); state = fx_flac_process(flac_, reinterpret_cast(buf.data()), &bytes_used, NULL, NULL); return bytes_used; }); } while (state != FLAC_END_OF_METADATA && !eof); if (state != FLAC_END_OF_METADATA) { if (state == FLAC_ERR) { return cpp::fail(Error::kMalformedData); } else { return cpp::fail(Error::kOutOfInput); } } int64_t channels = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_CHANNELS); int64_t fs = fx_flac_get_streaminfo(flac_, FLAC_KEY_SAMPLE_RATE); if (channels == FLAC_INVALID_METADATA_KEY || fs == FLAC_INVALID_METADATA_KEY) { return cpp::fail(Error::kMalformedData); } OutputFormat format{ .num_channels = static_cast(channels), .sample_rate_hz = static_cast(fs), }; uint64_t num_samples = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_SAMPLES); if (num_samples > 0) { format.total_samples = num_samples * channels; } return format; } auto FoxenFlacDecoder::DecodeTo(cpp::span output) -> cpp::result { bool is_eof = buffer_.Refill(input_.get()); cpp::span output32{reinterpret_cast(output.data()), output.size() / 2}; uint32_t samples_written = output32.size(); fx_flac_state_t state; buffer_.ConsumeBytes([&](cpp::span buf) -> size_t { uint32_t bytes_read = buf.size_bytes(); state = fx_flac_process(flac_, reinterpret_cast(buf.data()), &bytes_read, output32.data(), &samples_written); return bytes_read; }); if (state == FLAC_ERR) { return cpp::fail(Error::kMalformedData); } for (size_t i = 0; i < samples_written; i++) { output[i] = output32[i] >> 16; } return OutputInfo{.samples_written = samples_written, .is_stream_finished = samples_written == 0 && is_eof}; } auto FoxenFlacDecoder::SeekTo(size_t target) -> cpp::result { return {}; } } // namespace codecs