Add current playback timestamps

custom
jacqueline 2 years ago
parent 23ecff1011
commit b58b072d2d
  1. 4
      src/audio/audio_fsm.cpp
  2. 36
      src/audio/audio_task.cpp
  3. 4
      src/audio/i2s_audio_output.cpp
  4. 5
      src/audio/include/audio_events.hpp
  5. 4
      src/audio/include/audio_fsm.hpp

@ -111,6 +111,10 @@ void Playback::react(const PlayFile& ev) {
sTrackQueue.push_back(EnqueuedItem(ev.filename)); sTrackQueue.push_back(EnqueuedItem(ev.filename));
} }
void Playback::react(const PlaybackUpdate& ev) {
ESP_LOGI(kTag, "elapsed: %lu", ev.seconds_elapsed);
}
void Playback::react(const InputFileOpened& ev) {} void Playback::react(const InputFileOpened& ev) {}
void Playback::react(const InputFileFinished& ev) { void Playback::react(const InputFileFinished& ev) {

@ -62,6 +62,10 @@ void AudioTaskMain(std::unique_ptr<Pipeline> pipeline, IAudioSink* sink) {
std::vector<Pipeline*> all_elements = pipeline->GetIterationOrder(); std::vector<Pipeline*> all_elements = pipeline->GetIterationOrder();
float current_sample_in_second = 0;
uint32_t previous_second = 0;
uint32_t current_second = 0;
bool previously_had_work = false; bool previously_had_work = false;
events::EventQueue& event_queue = events::EventQueue::GetInstance(); events::EventQueue& event_queue = events::EventQueue::GetInstance();
while (1) { while (1) {
@ -78,6 +82,10 @@ void AudioTaskMain(std::unique_ptr<Pipeline> pipeline, IAudioSink* sink) {
} }
} }
if (!has_work) {
has_work = !xStreamBufferIsEmpty(sink->buffer());
}
if (previously_had_work && !has_work) { if (previously_had_work && !has_work) {
events::Dispatch<AudioPipelineIdle, AudioState>({}); events::Dispatch<AudioPipelineIdle, AudioState>({});
} }
@ -127,6 +135,10 @@ void AudioTaskMain(std::unique_ptr<Pipeline> pipeline, IAudioSink* sink) {
if (sink_stream.info().bytes_in_stream == 0) { if (sink_stream.info().bytes_in_stream == 0) {
if (sink_stream.is_producer_finished()) { if (sink_stream.is_producer_finished()) {
sink_stream.mark_consumer_finished(); sink_stream.mark_consumer_finished();
current_second = 0;
previous_second = 0;
current_sample_in_second = 0;
} else { } else {
// The user is probably about to hear a skip :( // The user is probably about to hear a skip :(
ESP_LOGW(kTag, "!! audio sink is underbuffered !!"); ESP_LOGW(kTag, "!! audio sink is underbuffered !!");
@ -155,6 +167,30 @@ void AudioTaskMain(std::unique_ptr<Pipeline> pipeline, IAudioSink* sink) {
xStreamBufferSend(sink->buffer(), sink_stream.data().data(), xStreamBufferSend(sink->buffer(), sink_stream.data().data(),
sink_stream.data().size_bytes(), 0); sink_stream.data().size_bytes(), 0);
if (std::holds_alternative<StreamInfo::Pcm>(*output_format)) {
StreamInfo::Pcm pcm = std::get<StreamInfo::Pcm>(*output_format);
float samples_sunk = bytes_sunk;
samples_sunk /= pcm.channels;
int8_t bps = pcm.bits_per_sample;
if (bps == 24) {
bps = 32;
}
samples_sunk /= (bps / 8);
current_sample_in_second += samples_sunk;
while (current_sample_in_second >= pcm.sample_rate) {
current_second++;
current_sample_in_second -= pcm.sample_rate;
}
if (previous_second != current_second) {
events::Dispatch<PlaybackUpdate, AudioState>(
{.seconds_elapsed = current_second});
}
previous_second = current_second;
}
// Adjust how long we wait for the next iteration if we're getting too far // Adjust how long we wait for the next iteration if we're getting too far
// ahead or behind. // ahead or behind.
float sunk_percent = static_cast<float>(bytes_sunk) / float sunk_percent = static_cast<float>(bytes_sunk) /

@ -129,8 +129,8 @@ auto I2SAudioOutput::Configure(const StreamInfo::Format& format) -> bool {
return true; return true;
} }
ESP_LOGI(kTag, "incoming audio stream: %u bpp @ %lu Hz", pcm.bits_per_sample, ESP_LOGI(kTag, "incoming audio stream: %u ch %u bpp @ %lu Hz", pcm.channels,
pcm.sample_rate); pcm.bits_per_sample, pcm.sample_rate);
drivers::I2SDac::Channels ch; drivers::I2SDac::Channels ch;
switch (pcm.channels) { switch (pcm.channels) {

@ -6,6 +6,7 @@
#pragma once #pragma once
#include <stdint.h>
#include <string> #include <string>
#include "tinyfsm.hpp" #include "tinyfsm.hpp"
@ -23,6 +24,10 @@ struct PlayTrack : tinyfsm::Event {
std::optional<database::TrackData> data; std::optional<database::TrackData> data;
}; };
struct PlaybackUpdate : tinyfsm::Event {
uint32_t seconds_elapsed;
};
struct InputFileOpened : tinyfsm::Event {}; struct InputFileOpened : tinyfsm::Event {};
struct InputFileFinished : tinyfsm::Event {}; struct InputFileFinished : tinyfsm::Event {};
struct AudioPipelineIdle : tinyfsm::Event {}; struct AudioPipelineIdle : tinyfsm::Event {};

@ -44,6 +44,8 @@ class AudioState : public tinyfsm::Fsm<AudioState> {
virtual void react(const PlayTrack&) {} virtual void react(const PlayTrack&) {}
virtual void react(const PlayFile&) {} virtual void react(const PlayFile&) {}
virtual void react(const PlaybackUpdate&) {}
virtual void react(const InputFileOpened&) {} virtual void react(const InputFileOpened&) {}
virtual void react(const InputFileFinished&) {} virtual void react(const InputFileFinished&) {}
virtual void react(const AudioPipelineIdle&) {} virtual void react(const AudioPipelineIdle&) {}
@ -87,6 +89,8 @@ class Playback : public AudioState {
void react(const PlayTrack&) override; void react(const PlayTrack&) override;
void react(const PlayFile&) override; void react(const PlayFile&) override;
void react(const PlaybackUpdate&) override;
void react(const InputFileOpened&) override; void react(const InputFileOpened&) override;
void react(const InputFileFinished&) override; void react(const InputFileFinished&) override;
void react(const AudioPipelineIdle&) override; void react(const AudioPipelineIdle&) override;

Loading…
Cancel
Save