Files
terebi/Sources/Core/progress_reporter.hpp
T

96 lines
3.1 KiB
C++

#pragma once
#include "player.h"
#include <array>
#include <atomic>
#include <condition_variable>
#include <deque>
#include <functional>
#include <mutex>
#include <string>
#include <map>
#include <memory>
#include <set>
#include <sys/types.h>
#include <string_view>
#include <thread>
namespace playback {
// The decoder owns media/snapshot methods; the writer owns the file after construction.
class ProgressReporter {
public:
explicit ProgressReporter(const std::string &path, std::function<double()> clock = {});
~ProgressReporter();
ProgressReporter(const ProgressReporter &) = delete;
ProgressReporter &operator=(const ProgressReporter &) = delete;
static bool validMediaURL(std::string_view url) noexcept;
static bool validMediaIdentity(std::string_view identity) noexcept;
void begin(const std::string &mediaURL, bool live = false) noexcept;
void observe(const PlayerState &state) noexcept;
void closeMedia() noexcept;
// Call after the decoder joins; drains queued records and joins the writer.
void finish() noexcept;
// Reopen only this session's original private inode, never an arbitrary existing file.
void resume();
std::string error() const;
private:
struct Snapshot {
double position = 0;
double duration = 0;
PlayerStatus status = PLAYER_EMPTY;
bool eligible = false;
} snapshot;
std::string mediaURL;
std::string path;
dev_t device = 0;
ino_t inode = 0;
std::function<double()> clock;
bool live = false;
bool hasSnapshot = false;
bool awaitingReady = false;
bool seekPending = false;
bool thresholdReported = false;
bool finished = false;
double lastRecordAt = 0;
int descriptor = -1;
std::thread writer;
mutable std::mutex mutex;
std::condition_variable wake;
std::deque<std::string> records;
std::array<char, 512> failure{};
std::atomic<bool> disabled{false};
bool stopping = false;
bool emit(const char *event) noexcept;
void disable(const char *message, int osError = 0) noexcept;
void writeRecords() noexcept;
};
// Routes decoder-owned snapshots by immutable media identity; only the active writer runs.
class ProgressReports {
public:
explicit ProgressReports(const std::string &path);
ProgressReports() = default;
void setSingleFile(const std::string &path);
void registerFile(const std::string &identity, const std::string &path);
void registerFiles(const char *const *identities, const char *const *paths, int count);
void begin(const std::string &identity, bool live = false) noexcept;
void observe(const PlayerState &state) noexcept;
void closeMedia() noexcept;
void finish() noexcept;
std::string error() const;
private:
struct Entry { std::string path; std::unique_ptr<ProgressReporter> reporter; };
std::unique_ptr<ProgressReporter> single;
std::string singlePath;
std::string singleIdentity;
std::map<std::string, Entry> entries;
std::set<std::string> paths;
ProgressReporter *active = nullptr;
mutable std::mutex mutex;
std::string failure;
};
}