feat(downstream): add cvmmap downstream runtime implementation

This commit introduces the full downstream runtime implementation needed to ingest, transform, and publish streams.

It preserves the original upstream request boundary by packaging the entire cvmmap-streamer module (build config, public API, protocol and IPC glue, and simulator/tester entrypoints) in one coherent core unit.

Keeping this group isolated enables reviewers to validate runtime behavior and correctness without mixing test evidence or process documentation changes.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-05 20:31:58 +08:00
commit 56e874ab6d
27 changed files with 8483 additions and 0 deletions
@@ -0,0 +1,84 @@
#pragma once
#include "cvmmap_streamer/config/runtime_config.hpp"
#include <chrono>
#include <cstdint>
#include <expected>
#include <span>
#include <string>
#include <string_view>
#include <vector>
namespace cvmmap_streamer::protocol {
struct RtmpPublisherStats {
std::uint64_t access_units{0};
std::uint64_t access_unit_bytes{0};
std::uint64_t video_messages{0};
std::uint64_t bytes_sent{0};
std::uint64_t send_errors{0};
std::uint64_t publish_failures{0};
std::uint64_t reconnect_attempts{0};
std::uint64_t reconnect_successes{0};
std::uint64_t reconnect_failures{0};
};
class RtmpPublisher {
public:
RtmpPublisher() = default;
~RtmpPublisher();
RtmpPublisher(const RtmpPublisher &) = delete;
RtmpPublisher &operator=(const RtmpPublisher &) = delete;
RtmpPublisher(RtmpPublisher &&other) noexcept;
RtmpPublisher &operator=(RtmpPublisher &&other) noexcept;
[[nodiscard]]
static std::expected<RtmpPublisher, std::string> create(const RuntimeConfig &config);
[[nodiscard]]
std::expected<void, std::string> publish_access_unit(std::span<const std::uint8_t> access_unit, std::uint64_t pts_ns);
[[nodiscard]]
const RtmpPublisherStats &stats() const;
void on_stream_reset();
void log_metrics() const;
private:
struct Session {
std::string original_url{};
std::string host{};
std::uint16_t port{1935};
std::string app{};
std::string stream{};
std::string tc_url{};
int socket_fd{-1};
std::uint32_t out_chunk_size{128};
std::uint32_t stream_id{1};
bool sequence_header_sent{false};
std::uint32_t reconnect_backoff_ms{250};
std::uint32_t consecutive_reconnect_failures{0};
std::chrono::steady_clock::time_point reconnect_due_at{};
bool in_cooldown{false};
};
[[nodiscard]]
std::expected<void, std::string> connect_session(Session &session);
void schedule_reconnect(Session &session, std::string_view reason, bool startup_path);
void close_session(Session &session);
CodecType codec_{CodecType::H264};
RtmpMode mode_{RtmpMode::Enhanced};
std::vector<Session> sessions_{};
RtmpPublisherStats stats_{};
bool had_successful_video_message_{false};
bool warned_all_sessions_closed_{false};
};
}