Skip to content

feat(stream): export per-session FEC metrics to CSV#5094

Draft
cesarpmorais wants to merge 6 commits into
LizardByte:masterfrom
cesarpmorais:feat/session-metrics-csv
Draft

feat(stream): export per-session FEC metrics to CSV#5094
cesarpmorais wants to merge 6 commits into
LizardByte:masterfrom
cesarpmorais:feat/session-metrics-csv

Conversation

@cesarpmorais
Copy link
Copy Markdown

@cesarpmorais cesarpmorais commented May 10, 2026

Description

Adds an opt-in mechanism to export per-session network metrics to CSV. When metrics_path is configured, Sunshine writes one CSV row per SS_FRAME_FEC_STATUS (0x5502) message received from the client, capturing FEC packet counts, missing-packet counts, and accumulated IDR requests.

Context

This is the first of two PRs working toward server-side adaptive bitrate for Sunshine. The current behavior — fixed bitrate negotiated once at RTSP handshake — has no feedback loop when network conditions degrade mid-session. The client-side "slow connection" toast in Moonlight is informational only; it doesn't trigger any server response.

To build a server-side controller, the server first needs observable signal about what the client is experiencing. This PR fills that gap by surfacing the existing SS_FRAME_FEC_STATUS stream (currently dropped by Sunshine) as a CSV-exportable feed. A follow-up PR will propose a controller that consumes this signal to adjust bitrate dynamically.

Motivation

Sunshine receives SS_FRAME_FEC_STATUS from Moonlight clients but silently drops it today — the packet type has no registered handler and the message hits the type [Unknown] branch in stream.cpp. This is the richest per-frame loss signal in the protocol; exposing it gives operators and developers a concrete view of network conditions experienced by the client, regardless of whether they care about adaptive bitrate.

Changes

  • New config option metrics_path (string, default empty = disabled)
  • New handler for SS_FRAME_FEC_PTYPE (0x5502) in controlBroadcastThread
  • Wire-format struct + endian-aware decoding for SS_FRAME_FEC_STATUS
  • Per-session lazy-open std::ofstream — no file is created until the first event arrives
  • Existing IDR_FRAME handler increments a counter that is flushed on each row
  • 5 unit tests covering header, big-endian decoding, short-payload rejection, metadata embedding, and filename format
  • Documentation in docs/configuration.md

Behavior

  • Default: disabled. Zero overhead — no allocations, no file handles, no extra syscalls.
  • Enabled, clean network: zero events received → no file created. The Moonlight client only emits SS_FRAME_FEC_STATUS when there is FEC recovery activity or a frame drop (see moonlight-common-c/src/RtpVideoQueue.c:reportFinalFrameFecStatus). A lossless LAN session produces an empty metrics_path directory.
  • Enabled, lossy network: file sunshine_metrics_<session_id>_<unix_ms>.csv per session, one row per FEC event with the schema documented in docs/configuration.md.
  • Handler runs on the control thread — no impact on encoding/transmit threads.

Test plan

  • Unit tests pass (MetricsCsvTests.* — 5 tests)
  • Empirically validated end-to-end: 5 min Moonlight Android session with tc netem loss 5% on the server interface produced 155 events. Loss patterns correlate with IDR clusters; FEC field values match the wire format spec.
  • Verified default-disabled path produces no file system activity.

Screenshot

N/A (no UI changes)

Issues Fixed or Closed

N/A

Roadmap Issues

N/A

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@sonarqubecloud
Copy link
Copy Markdown

@cesarpmorais cesarpmorais marked this pull request as draft May 10, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant