Files
AnyPS5/core/libs/prx/libSceVideoOut/include/Telemetry.hpp
T
Eli Yarson b8607f4ced feat(videoout): write pad and present telemetry to APS5_VIDEOOUT_TELEMETRY_DIR
APS5_VIDEOOUT_TELEMETRY_DIR=<directory> appends one JSON object per line to <directory>/videoout.jsonl: a contract line for the run (commit and pid), a pad line whenever the published pad state changes in its buttons, sticks, L2 or R2, a present line after the first present and every 30 after that with the count and rate the window title shows, and a drops line with the number of lines the writer discarded, reported every ten seconds while it grows and once at a normal exit. A bounded queue of 4096 lines and one writer thread batch the file, so neither the present nor the input path waits for it; a pad change that the full queue refused stays pending for a later publish, and the frame count moves from UpdateTitle's function-static to DisplayWindow so the input path can name the present it belongs to.

Without the variable no file is opened and no thread is started: a present or an input update costs one call that checks a guard variable and returns null.
2026-10-19 15:27:49 +02:00

75 lines
1.8 KiB
C++

#ifndef CORE_LIBS_PRX_LIBSCEVIDEOOUT_INCLUDE_TELEMETRY_HPP
#define CORE_LIBS_PRX_LIBSCEVIDEOOUT_INCLUDE_TELEMETRY_HPP
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <fstream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include "prx/libScePad/include/PadState.hpp"
namespace VideoOutTelemetry {
class BoundedLineQueue {
public:
explicit BoundedLineQueue(std::size_t capacity);
bool TryPush(std::string line);
bool Push(std::string line);
std::deque<std::string> Drain();
std::uint64_t Dropped() const;
private:
bool pushLocked(std::string line);
std::mutex mutex;
std::deque<std::string> lines;
std::size_t capacity;
std::atomic<std::uint64_t> dropped{0};
};
class Writer {
public:
Writer(const std::string& directory, std::size_t capacity, const std::string& commit);
~Writer();
Writer(const Writer&) = delete;
Writer& operator=(const Writer&) = delete;
bool EmitPad(std::uint64_t frame, const PadInputState& state);
void EmitPresent(std::uint64_t frame, double fps);
std::uint64_t Dropped() const;
private:
bool emit(std::string line, bool mustKeep);
void run(std::stop_token token);
void writeAll(const std::string& text);
void writeDrops(bool force);
std::ofstream output;
BoundedLineQueue queue;
std::uint64_t reportedDrops = 0;
std::jthread thread;
};
class PadChangeFilter {
public:
bool Changed(const PadInputState& state) const;
void Commit(const PadInputState& state);
private:
PadInputState last{};
};
bool EmitPadIfChanged(Writer& writer, PadChangeFilter& filter, std::uint64_t frame, const PadInputState& state);
std::unique_ptr<Writer> OpenFromEnvironment(const char* directory, const std::string& commit);
Writer* Instance();
}
#endif