#pragma once #include "debug_settings.h" #include "upnp/stream_server.h" #include #include #include #include #include #include // Per-response measurements; no TCP_INFO calls or logging when disabled. class StreamDebugRequest : public upnp::StreamRequest { upnp::StreamRequest& request; std::function now; bool enabled, begun = false; unsigned next = 1; uint64_t sent = 0, wireBase = UINT64_MAX; double longest = 0; std::chrono::steady_clock::time_point started; std::function audio; uint64_t base = 0; void line(bool final) { if (!enabled || !begun) return; const double seconds = std::chrono::duration(now()-started).count(); if (!final && seconds < next) return; const auto lead = int64_t(audio ? audio() - base : 0) - int64_t(seconds*1000); const uint64_t wire = request.connectionSentBytes(); if (wire != UINT64_MAX) { sent = wire - wireBase; wireBase = wire; } printf("stream %s: debug t=%.3f lead_ms=%lld bytes=%llu send_max_ms=%.3f %s%s\n", parameter("stream").c_str(), seconds, (long long)lead, (unsigned long long)sent, longest, request.connectionDiagnostics().c_str(), final ? " final" : ""); sent = 0; longest = 0; next = seconds < 30 ? unsigned(seconds)+1 : (unsigned(seconds)/10+1)*10; } public: explicit StreamDebugRequest(upnp::StreamRequest& request, std::function clock = std::chrono::steady_clock::now) : request(request), now(std::move(clock)) { enabled = bridge::debugOption("stream", "YENEY_DEBUG_STREAM"); } ~StreamDebugRequest() { if (enabled && begun) { request.peerClosed(); line(true); } } void encoder(std::function clock, bool continuation = false) { audio = std::move(clock); base = continuation ? audio() : 0; } std::string path() const override { return request.path(); } Method method() const override { return request.method(); } std::string parameter(const std::string& name) const override { return request.parameter(name); } upnp::RequestHeaders headers() const override { return request.headers(); } std::string serverName() const override { return request.serverName(); } std::string connectionDiagnostics() const override { return request.connectionDiagnostics(); } bool aborted() const override { return request.aborted(); } void sendTimeout(unsigned ms) override { request.sendTimeout(ms); } void reply(unsigned status,const std::string& type = {}) override { request.reply(status,type); } void disconnect() override { request.disconnect(); } bool peerClosed() override { const bool closed = request.peerClosed(); line(false); return closed; } bool send(const char* data,size_t size) override { if (!enabled) return request.send(data,size); if (!begun) { begun = true; wireBase = request.connectionSentBytes(); started = now(); } const auto before = now(); const bool ok = request.send(data,size); longest = std::max(longest,std::chrono::duration(now()-before).count()); if (ok) sent += size; line(false); return ok; } };