fix: use TAI-time-based grain index alignment in passthrough

Instead of chasing headIndex from mxlFlowReaderGetRuntimeInfo (which
points to the NEXT grain to be written, causing perpetual TOO_EARLY),
the passthrough now uses mxlTimestampToIndex + mxlGetNsUntilIndex for
proper timing alignment, matching the pattern used by mxl-gst-sink.

Key changes:
- realign() computes read_index from current TAI time minus 1 grain delay
- process() uses mxlSleepForNs to wait until the target grain is due
- on_add_reader fetches grain_rate from mxlFlowConfigInfo
- Removed separate write_index_ (uses grain_info.index for writer)
This commit is contained in:
Johanness
2026-05-26 22:40:46 +03:00
parent 3e1477c56c
commit 2c712592dd
2 changed files with 29 additions and 12 deletions
+25 -9
View File
@@ -2,6 +2,7 @@
#include <mxl/flow.h> #include <mxl/flow.h>
#include <mxl/mxl.h> #include <mxl/mxl.h>
#include <mxl/time.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
@@ -19,10 +20,14 @@ void PassthroughNode::on_add_writer(const std::string& port_id, mxlFlowWriter wr
void PassthroughNode::on_add_reader(const std::string& port_id, mxlFlowReader reader) { void PassthroughNode::on_add_reader(const std::string& port_id, mxlFlowReader reader) {
if (port_id == "video_in") { if (port_id == "video_in") {
reader_ = reader; reader_ = reader;
mxlFlowRuntimeInfo runtime{};
mxlFlowReaderGetRuntimeInfo(*reader_, &runtime); mxlFlowConfigInfo config{};
read_index_ = runtime.headIndex; mxlFlowReaderGetConfigInfo(*reader_, &config);
spdlog::info("Passthrough: reader added on video_in, starting at index {}", read_index_); grain_rate_ = config.common.grainRate;
realign();
spdlog::info("Passthrough: reader added on video_in, grain_rate={}/{}, read_index={}",
grain_rate_.numerator, grain_rate_.denominator, read_index_);
} }
} }
@@ -40,21 +45,32 @@ void PassthroughNode::on_remove_reader(const std::string& port_id) {
} }
} }
void PassthroughNode::realign() {
auto now = mxlGetTime();
auto current_index = mxlTimestampToIndex(&grain_rate_, now);
constexpr int64_t read_delay_grains = 1;
read_index_ = current_index - read_delay_grains;
aligned_ = true;
}
void PassthroughNode::process() { void PassthroughNode::process() {
if (!reader_ || !writer_) { if (!reader_ || !writer_ || !aligned_) {
return; return;
} }
auto wait_ns = mxlGetNsUntilIndex(read_index_, &grain_rate_);
if (wait_ns > 0 && wait_ns < 500000000ULL) {
mxlSleepForNs(wait_ns);
}
mxlGrainInfo grain_info{}; mxlGrainInfo grain_info{};
uint8_t* payload = nullptr; uint8_t* payload = nullptr;
auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 20000000ULL, &grain_info, &payload); auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 20000000ULL, &grain_info, &payload);
if (status != MXL_STATUS_OK) { if (status != MXL_STATUS_OK) {
if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE || status == MXL_ERR_OUT_OF_RANGE_TOO_EARLY) { if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE || status == MXL_ERR_OUT_OF_RANGE_TOO_EARLY) {
mxlFlowRuntimeInfo runtime{}; spdlog::warn("Passthrough: index {} out of range ({}), realigning", read_index_, static_cast<int>(status));
mxlFlowReaderGetRuntimeInfo(*reader_, &runtime); realign();
spdlog::warn("Passthrough: index {} out of range, jumping to head {}", read_index_, runtime.headIndex);
read_index_ = runtime.headIndex;
} }
return; return;
} }
+4 -3
View File
@@ -4,7 +4,6 @@
#include <mxl/flow.h> #include <mxl/flow.h>
#include <unordered_map>
#include <optional> #include <optional>
namespace dmf_node { namespace dmf_node {
@@ -34,12 +33,14 @@ public:
nlohmann::json status() const override; nlohmann::json status() const override;
private: private:
void realign();
std::optional<mxlFlowReader> reader_; std::optional<mxlFlowReader> reader_;
std::optional<mxlFlowWriter> writer_; std::optional<mxlFlowWriter> writer_;
mxlInstance mxl_instance_ = nullptr; mxlRational grain_rate_{50, 1};
uint64_t read_index_ = 0; uint64_t read_index_ = 0;
uint64_t write_index_ = 0;
uint64_t grains_processed_ = 0; uint64_t grains_processed_ = 0;
bool aligned_ = false;
}; };
} // namespace dmf_node } // namespace dmf_node