Add duration for flacs

custom
jacqueline 2 years ago
parent 0a8d2fd12e
commit cdaa2ac97a
  1. 68
      src/audio/audio_task.cpp
  2. 19
      src/audio/include/audio_task.hpp
  3. 14
      src/codecs/foxenflac.cpp

@ -53,20 +53,23 @@ static const char* kTag = "audio_dec";
static constexpr std::size_t kSampleBufferSize = 16 * 1024; static constexpr std::size_t kSampleBufferSize = 16 * 1024;
Timer::Timer(StreamInfo::Pcm format) Timer::Timer(const StreamInfo::Pcm& format, const Duration& duration)
: format_(format), : format_(format), current_seconds_(0), current_sample_in_second_(0) {
current_seconds_(0), switch (duration.src) {
current_sample_in_second_(0), case Duration::Source::kLibTags:
total_duration_seconds_(0) {} ESP_LOGI(kTag, "using duration from libtags");
total_duration_seconds_ = duration.duration;
auto Timer::SetLengthSeconds(uint32_t len) -> void { break;
total_duration_seconds_ = len; case Duration::Source::kCodec:
has_duration_ = true; ESP_LOGI(kTag, "using duration from decoder");
} total_duration_seconds_ = duration.duration;
break;
auto Timer::SetLengthBytes(uint32_t len) -> void { case Duration::Source::kFileSize:
total_duration_seconds_ = bytes_to_samples(len) / format_.sample_rate; ESP_LOGW(kTag, "calculating duration from filesize");
has_duration_ = true; total_duration_seconds_ =
bytes_to_samples(duration.duration) / format_.sample_rate;
break;
}
} }
auto Timer::AddBytes(std::size_t bytes) -> void { auto Timer::AddBytes(std::size_t bytes) -> void {
@ -137,14 +140,6 @@ void AudioTask::Main() {
if (ForwardPcmStream(*pcm, stream.data())) { if (ForwardPcmStream(*pcm, stream.data())) {
stream.consume(stream.data().size_bytes()); stream.consume(stream.data().size_bytes());
} }
if (!timer_->has_duration()) {
if (stream.info().total_length_seconds()) {
timer_->SetLengthSeconds(*stream.info().total_length_seconds());
} else {
timer_->SetLengthBytes(
stream.info().total_length_bytes().value_or(0));
}
}
return; return;
} }
@ -235,16 +230,20 @@ auto AudioTask::BeginDecoding(InputStream& stream) -> bool {
.sample_rate = format.sample_rate_hz, .sample_rate = format.sample_rate_hz,
}; };
if (!ConfigureSink(new_format)) { Duration duration;
return false;
}
if (format.duration_seconds) { if (format.duration_seconds) {
timer_->SetLengthSeconds(*format.duration_seconds); duration.src = Duration::Source::kCodec;
duration.duration = *format.duration_seconds;
} else if (stream.info().total_length_seconds()) { } else if (stream.info().total_length_seconds()) {
timer_->SetLengthSeconds(*stream.info().total_length_seconds()); duration.src = Duration::Source::kLibTags;
duration.duration = *stream.info().total_length_seconds();
} else { } else {
timer_->SetLengthBytes(stream.info().total_length_bytes().value_or(0)); duration.src = Duration::Source::kFileSize;
duration.duration = *stream.info().total_length_bytes();
}
if (!ConfigureSink(new_format, duration)) {
return false;
} }
return true; return true;
@ -307,7 +306,11 @@ auto AudioTask::ForwardPcmStream(StreamInfo::Pcm& format,
cpp::span<const std::byte> samples) -> bool { cpp::span<const std::byte> samples) -> bool {
// First we need to reconfigure the sink for this sample format. // First we need to reconfigure the sink for this sample format.
if (format != current_output_format_) { if (format != current_output_format_) {
if (!ConfigureSink(format)) { Duration d{
.src = Duration::Source::kFileSize,
.duration = samples.size_bytes(),
};
if (!ConfigureSink(format, d)) {
return false; return false;
} }
} }
@ -319,7 +322,8 @@ auto AudioTask::ForwardPcmStream(StreamInfo::Pcm& format,
return true; return true;
} }
auto AudioTask::ConfigureSink(const StreamInfo::Pcm& format) -> bool { auto AudioTask::ConfigureSink(const StreamInfo::Pcm& format,
const Duration& duration) -> bool {
if (format != current_output_format_) { if (format != current_output_format_) {
// The new format is different to the old one. Wait for the sink to drain // The new format is different to the old one. Wait for the sink to drain
// before continuing. // before continuing.
@ -337,7 +341,7 @@ auto AudioTask::ConfigureSink(const StreamInfo::Pcm& format) -> bool {
} }
current_output_format_ = format; current_output_format_ = format;
timer_.reset(new Timer(format)); timer_.reset(new Timer(format, duration));
return true; return true;
} }

@ -18,15 +18,21 @@
namespace audio { namespace audio {
struct Duration {
enum class Source {
kLibTags,
kCodec,
kFileSize,
};
Source src;
uint32_t duration;
};
class Timer { class Timer {
public: public:
explicit Timer(StreamInfo::Pcm); Timer(const StreamInfo::Pcm&, const Duration&);
auto SetLengthSeconds(uint32_t) -> void;
auto SetLengthBytes(uint32_t) -> void;
auto AddBytes(std::size_t) -> void; auto AddBytes(std::size_t) -> void;
auto has_duration() const -> bool { return has_duration_; }
private: private:
auto bytes_to_samples(uint32_t) -> uint32_t; auto bytes_to_samples(uint32_t) -> uint32_t;
@ -36,7 +42,6 @@ class Timer {
uint32_t current_seconds_; uint32_t current_seconds_;
uint32_t current_sample_in_second_; uint32_t current_sample_in_second_;
bool has_duration_;
uint32_t total_duration_seconds_; uint32_t total_duration_seconds_;
}; };
@ -57,7 +62,7 @@ class AudioTask {
auto ForwardPcmStream(StreamInfo::Pcm&, cpp::span<const std::byte>) -> bool; auto ForwardPcmStream(StreamInfo::Pcm&, cpp::span<const std::byte>) -> bool;
auto ConfigureSink(const StreamInfo::Pcm&) -> bool; auto ConfigureSink(const StreamInfo::Pcm&, const Duration&) -> bool;
IAudioSource* source_; IAudioSource* source_;
IAudioSink* sink_; IAudioSink* sink_;

@ -6,6 +6,7 @@
#include "foxenflac.hpp" #include "foxenflac.hpp"
#include <stdint.h> #include <stdint.h>
#include <sys/_stdint.h>
#include <cstdlib> #include <cstdlib>
@ -44,13 +45,20 @@ auto FoxenFlacDecoder::BeginStream(const cpp::span<const std::byte> input)
return {bytes_used, cpp::fail(Error::kMalformedData)}; return {bytes_used, cpp::fail(Error::kMalformedData)};
} }
return {bytes_used, OutputFormat format{
OutputFormat{
.num_channels = static_cast<uint8_t>(channels), .num_channels = static_cast<uint8_t>(channels),
.bits_per_sample = 32, // libfoxenflac output is fixed-size. .bits_per_sample = 32, // libfoxenflac output is fixed-size.
.sample_rate_hz = static_cast<uint32_t>(fs), .sample_rate_hz = static_cast<uint32_t>(fs),
.duration_seconds = {}, .duration_seconds = {},
}}; .bits_per_second = {},
};
uint64_t num_samples = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_SAMPLES);
if (num_samples > 0) {
format.duration_seconds = num_samples / fs;
}
return {bytes_used, format};
} }
auto FoxenFlacDecoder::ContinueStream(cpp::span<const std::byte> input, auto FoxenFlacDecoder::ContinueStream(cpp::span<const std::byte> input,

Loading…
Cancel
Save