Ctrl K
ComunidadGuías…

consumption_diagnostic.h

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
#pragma once
#include "upnp/stream_server.h"
#include "player_name.h"
#include <chrono>
#include <atomic>
#include <condition_variable>
#include <cstdio>
#include <mutex>
#include <thread>

namespace bridge {
inline uint64_t consumptionTimeMs() {
    return std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::steady_clock::now().time_since_epoch()).count();
}
// One native player/room per process. This is the core TIMING-01 callback,
// independent of SHM publication settings. It describes the next offered block,
// not a claim that this sample is already in the speaker's HTTP buffer.
struct ContentObservation {
    std::mutex mutex;
    uint64_t frame = 0, at = 0;
    bool known = false;
    void set(uint64_t value, bool valid) {
        std::lock_guard<std::mutex> lock(mutex);
        frame = value; known = valid; at = consumptionTimeMs();
    }
};
inline ContentObservation &consumptionContent() { static ContentObservation value; return value; }
inline std::string consumptionLine(uint64_t now, uint64_t served, int64_t backlog,
                                   uint64_t frame, bool known, uint64_t observed,
                                   const std::string &roomHex, const char *mode) {
    const auto bytes = served == UINT64_MAX ? "unknown" : std::to_string(served);
    const auto pending = backlog < 0 ? "unknown" : std::to_string(backlog);
    const auto audible = backlog < 0 || served == UINT64_MAX ? "unknown" :
        std::to_string(served > uint64_t(backlog) ? served - uint64_t(backlog) : 0);
    return "yeney: queue consume room_hex=" + roomHex + " mode=" + mode +
        " native_ms=" + std::to_string(now) + " served=" + bytes + " backlog=" + pending +
        " audible=" + audible + " content_frame=" + (known ? std::to_string(frame) : "unknown") +
        " content_observed_ms=" + std::to_string(observed) + "\n";
}
// Separate observer: stalled send/read calls cannot suppress the 1 Hz samples.
// No socket options, writes, transport calls or audio counters are changed.
class ConsumptionDiagnostic {
    std::mutex mutex;
    std::condition_variable changed;
    bool stopped = false;
    std::thread worker;
    inline static std::atomic<uint64_t> serial{0};
public:
    ConsumptionDiagnostic(upnp::StreamRequest &request, const std::string &room, const char *mode) {
        std::string hex;
        constexpr char digits[] = "0123456789abcdef";
        for (unsigned char c : room) { hex += digits[c >> 4]; hex += digits[c & 15]; }
        const auto connection = ++serial;
        worker = std::thread([this, &request, hex, mode, connection] {
            std::unique_lock<std::mutex> lock(mutex);
            auto next = std::chrono::steady_clock::now();
            while (!stopped) {
                const auto now = consumptionTimeMs();
                const auto served = request.connectionSentBytes();
                const auto backlog = request.connectionBacklog();
                auto &content = consumptionContent();
                std::string line;
                { std::lock_guard<std::mutex> contentLock(content.mutex);
                  line = consumptionLine(now, served, backlog, content.frame, content.known, content.at, hex, mode); }
                line.insert(line.size()-1, " connection=" + std::to_string(connection));
                std::fputs(line.c_str(), stdout);
                next += std::chrono::seconds(1);
                changed.wait_until(lock, next, [this] { return stopped; });
            }
        });
    }
    ~ConsumptionDiagnostic() {
        { std::lock_guard<std::mutex> lock(mutex); stopped = true; }
        changed.notify_one(); worker.join();
    }
};
} // namespace bridge