Reintroduce track timer, now relying more on codecs

custom
jacqueline 2 years ago
parent 958160aa54
commit c37ccb9851
  1. 56
      src/audio/audio_task.cpp
  2. 18
      src/audio/include/audio_task.hpp
  3. 2
      src/codecs/foxenflac.cpp
  4. 2
      src/codecs/include/codec.hpp
  5. 4
      src/codecs/mad.cpp
  6. 15
      src/codecs/opus.cpp
  7. 7
      src/codecs/vorbis.cpp

@ -56,31 +56,18 @@ static const char* kTag = "audio_dec";
static constexpr std::size_t kCodecBufferLength = 240 * 4; static constexpr std::size_t kCodecBufferLength = 240 * 4;
Timer::Timer(const StreamInfo::Pcm& format, const Duration& duration) Timer::Timer(uint32_t sample_rate, uint32_t total_samples)
: format_(format), current_seconds_(0), current_sample_in_second_(0) { : sample_rate_(sample_rate),
switch (duration.src) { current_seconds_(0),
case Duration::Source::kLibTags: current_sample_in_second_(0),
ESP_LOGI(kTag, "using duration from libtags"); total_duration_seconds_(total_samples / sample_rate) {}
total_duration_seconds_ = duration.duration;
break; auto Timer::AddSamples(std::size_t samples) -> void {
case Duration::Source::kCodec:
ESP_LOGI(kTag, "using duration from decoder");
total_duration_seconds_ = duration.duration;
break;
case Duration::Source::kFileSize:
ESP_LOGW(kTag, "calculating duration from filesize");
total_duration_seconds_ =
bytes_to_samples(duration.duration) / format_.sample_rate;
break;
}
}
auto Timer::AddBytes(std::size_t bytes) -> void {
bool incremented = false; bool incremented = false;
current_sample_in_second_ += bytes_to_samples(bytes); current_sample_in_second_ += samples;
while (current_sample_in_second_ >= format_.sample_rate) { while (current_sample_in_second_ >= sample_rate_) {
current_seconds_++; current_seconds_++;
current_sample_in_second_ -= format_.sample_rate; current_sample_in_second_ -= sample_rate_;
incremented = true; incremented = true;
} }
@ -96,18 +83,6 @@ auto Timer::AddBytes(std::size_t bytes) -> void {
} }
} }
auto Timer::bytes_to_samples(uint32_t bytes) -> uint32_t {
uint32_t samples = bytes;
samples /= format_.channels;
// Samples must be aligned to 16 bits. The number of actual bytes per
// sample is therefore the bps divided by 16, rounded up (align to word),
// times two (convert to bytes).
uint8_t bytes_per_sample = ((format_.bits_per_sample + 16 - 1) / 16) * 2;
samples /= bytes_per_sample;
return samples;
}
auto AudioTask::Start(IAudioSource* source, IAudioSink* sink) -> AudioTask* { auto AudioTask::Start(IAudioSource* source, IAudioSink* sink) -> AudioTask* {
AudioTask* task = new AudioTask(source, sink); AudioTask* task = new AudioTask(source, sink);
// Pin to CORE1 because codecs should be fixed point anyway, and being on // Pin to CORE1 because codecs should be fixed point anyway, and being on
@ -162,6 +137,13 @@ auto AudioTask::BeginDecoding(std::shared_ptr<codecs::IStream> stream) -> bool {
return false; return false;
} }
if (open_res->total_samples) {
timer_.reset(
new Timer(open_res->sample_rate_hz, open_res->total_samples.value()));
} else {
timer_.reset();
}
current_sink_format_ = IAudioSink::Format{ current_sink_format_ = IAudioSink::Format{
.sample_rate = open_res->sample_rate_hz, .sample_rate = open_res->sample_rate_hz,
.num_channels = open_res->num_channels, .num_channels = open_res->num_channels,
@ -183,6 +165,10 @@ auto AudioTask::ContinueDecoding() -> bool {
current_sink_format_.value(), res->is_stream_finished); current_sink_format_.value(), res->is_stream_finished);
} }
if (timer_) {
timer_->AddSamples(res->samples_written);
}
return res->is_stream_finished; return res->is_stream_finished;
} }

@ -21,26 +21,14 @@
namespace audio { namespace audio {
struct Duration {
enum class Source {
kLibTags,
kCodec,
kFileSize,
};
Source src;
uint32_t duration;
};
class Timer { class Timer {
public: public:
Timer(const StreamInfo::Pcm&, const Duration&); Timer(uint32_t sample_rate, uint32_t total_samples);
auto AddBytes(std::size_t) -> void; auto AddSamples(std::size_t) -> void;
private: private:
auto bytes_to_samples(uint32_t) -> uint32_t; uint32_t sample_rate_;
StreamInfo::Pcm format_;
uint32_t current_seconds_; uint32_t current_seconds_;
uint32_t current_sample_in_second_; uint32_t current_sample_in_second_;

@ -64,7 +64,7 @@ auto FoxenFlacDecoder::OpenStream(std::shared_ptr<IStream> input)
uint64_t num_samples = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_SAMPLES); uint64_t num_samples = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_SAMPLES);
if (num_samples > 0) { if (num_samples > 0) {
format.duration_seconds = num_samples / fs; format.total_samples = num_samples / fs;
} }
return format; return format;

@ -91,7 +91,7 @@ class ICodec {
struct OutputFormat { struct OutputFormat {
uint8_t num_channels; uint8_t num_channels;
uint32_t sample_rate_hz; uint32_t sample_rate_hz;
std::optional<uint32_t> duration_seconds; std::optional<uint32_t> total_samples;
bool operator==(const OutputFormat&) const = default; bool operator==(const OutputFormat&) const = default;
}; };

@ -92,7 +92,7 @@ auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input)
auto vbr_length = GetVbrLength(header); auto vbr_length = GetVbrLength(header);
if (vbr_length) { if (vbr_length) {
output.duration_seconds = vbr_length; output.total_samples = vbr_length;
} }
return output; return output;
} }
@ -234,7 +234,7 @@ auto MadMp3Decoder::GetVbrLength(const mad_header& header)
return {}; return {};
} }
return (double)(frames_count * samples_per_frame) / header.samplerate; return (double)(frames_count * samples_per_frame);
} }
} // namespace codecs } // namespace codecs

@ -122,9 +122,24 @@ auto XiphOpusDecoder::OpenStream(std::shared_ptr<IStream> input)
return cpp::fail(Error::kMalformedData); return cpp::fail(Error::kMalformedData);
} }
auto l = op_pcm_total(opus_, -1);
std::optional<uint32_t> length;
if (l > 0) {
// Output is always downmixed to two channels, but the pcm count does not
// reflect this.
int channels = op_channel_count(opus_, -1);
if (channels == 1) {
l *= 2;
} else if (channels > 2) {
l /= channels * 2;
}
length = l;
}
return OutputFormat{ return OutputFormat{
.num_channels = 2, .num_channels = 2,
.sample_rate_hz = 48000, .sample_rate_hz = 48000,
.total_samples = length,
}; };
} }

@ -118,9 +118,16 @@ auto TremorVorbisDecoder::OpenStream(std::shared_ptr<IStream> input)
return cpp::fail(Error::kMalformedData); return cpp::fail(Error::kMalformedData);
} }
auto l = ov_pcm_total(&vorbis_, -1);
std::optional<uint32_t> length;
if (l > 0) {
length = l;
}
return OutputFormat{ return OutputFormat{
.num_channels = static_cast<uint8_t>(info->channels), .num_channels = static_cast<uint8_t>(info->channels),
.sample_rate_hz = static_cast<uint32_t>(info->rate), .sample_rate_hz = static_cast<uint32_t>(info->rate),
.total_samples = length,
}; };
} }

Loading…
Cancel
Save