fix: LWS HTTP connection leak, grain index alignment, and reader head tracking

- control_server: add Connection: close header + always return -1 after
  HTTP response to force-close connection. Without this, lws_service()
  blocks forever after the first POST /cmd, freezing the node process loop.
- passthrough: initialize read_index_ to runtime.headIndex when reader
  is added (prevents TOO_EARLY errors on first read)
- passthrough: handle MXL_ERR_OUT_OF_RANGE_TOO_EARLY in addition to
  TOO_LATE (both jump to head index)
- passthrough: use grain_info.index as writer index instead of separate
  write_index_ counter (MXL writers must use TAI-based grain indices)
- passthrough: reduce grain read timeout from 100ms to 20ms for tighter
  loop with LWS poll
- node_runner: add 'status' command handler that sends node status
  back via control server
This commit is contained in:
Johanness
2026-05-26 22:22:46 +03:00
parent 5b2d420e71
commit 3e1477c56c
3 changed files with 26 additions and 14 deletions
+15 -13
View File
@@ -19,7 +19,10 @@ void PassthroughNode::on_add_writer(const std::string& port_id, mxlFlowWriter wr
void PassthroughNode::on_add_reader(const std::string& port_id, mxlFlowReader reader) {
if (port_id == "video_in") {
reader_ = reader;
spdlog::info("Passthrough: reader added on video_in");
mxlFlowRuntimeInfo runtime{};
mxlFlowReaderGetRuntimeInfo(*reader_, &runtime);
read_index_ = runtime.headIndex;
spdlog::info("Passthrough: reader added on video_in, starting at index {}", read_index_);
}
}
@@ -45,26 +48,23 @@ void PassthroughNode::process() {
mxlGrainInfo grain_info{};
uint8_t* payload = nullptr;
auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 100000000ULL, &grain_info, &payload);
auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 20000000ULL, &grain_info, &payload);
if (status != MXL_STATUS_OK) {
if (status == MXL_ERR_TIMEOUT) {
return;
}
if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE) {
if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE || status == MXL_ERR_OUT_OF_RANGE_TOO_EARLY) {
mxlFlowRuntimeInfo runtime{};
mxlFlowReaderGetRuntimeInfo(*reader_, &runtime);
spdlog::warn("Passthrough: index {} out of range, jumping to head {}", read_index_, runtime.headIndex);
read_index_ = runtime.headIndex;
return;
}
return;
}
mxlGrainInfo out_grain{};
uint8_t* out_payload = nullptr;
status = mxlFlowWriterOpenGrain(*writer_, write_index_, &out_grain, &out_payload);
status = mxlFlowWriterOpenGrain(*writer_, grain_info.index, &out_grain, &out_payload);
if (status != MXL_STATUS_OK) {
spdlog::warn("Passthrough: failed to open output grain at index {}: {}", write_index_, static_cast<int>(status));
read_index_++;
spdlog::warn("Passthrough: failed to open output grain at index {}: {}", grain_info.index, static_cast<int>(status));
read_index_ = grain_info.index + 1;
return;
}
@@ -75,9 +75,12 @@ void PassthroughNode::process() {
out_grain.flags = grain_info.flags;
mxlFlowWriterCommitGrain(*writer_, &out_grain);
read_index_++;
write_index_++;
read_index_ = grain_info.index + 1;
grains_processed_++;
if (grains_processed_ <= 5 || grains_processed_ % 50 == 0) {
spdlog::info("Passthrough: grain #{}, index={}, size={}", grains_processed_, grain_info.index, grain_info.grainSize);
}
}
nlohmann::json PassthroughNode::status() const {
@@ -85,7 +88,6 @@ nlohmann::json PassthroughNode::status() const {
{"type", "passthrough"},
{"grains_processed", grains_processed_},
{"read_index", read_index_},
{"write_index", write_index_},
{"has_reader", reader_.has_value()},
{"has_writer", writer_.has_value()},
};