feat(33): shed our own capture cost first; the task is done
Last slice. 590 green, 0 warnings. - **Shed before you charge the viewer.** On machine evidence the policy's first act is `ShedCaptureCadence`: `ScreenCaptureFrameSource` widens its conversion interval 10 ms → 33 ms (≈100 → 30 conversions/s) through a new `ScreenCaptureManager.ShedLoad`. The output tier, the declared fps and the viewer's picture are untouched — we stop paying for readbacks we were throwing away. It costs no step budget; if the starvation persists, the fps ladder runs on the next clean window. - The shed is reset on every stop path, so a cheap session cannot leave a later one capped. - **The session line is a Logs-tab line, not a session-report line.** The session report is the money summary (Super Chats, per currency); quality chatter there would bury the numbers it exists for. The cause-tagged line already lands in the log at the moment of the step. TASK 33 is complete: two ladders, budgets, floors, ambiguity, one-way with recovery behind a flag, the relaunch, the copy, and the cost shed. 18 tests pin the ladders, the copy and the restart.
This commit is contained in:
@@ -64,10 +64,14 @@ public sealed class ScreenCaptureFrameSource : IScreenCaptureSource
|
||||
// accommodate in-flight frames) and publishes only monotonically newer frames
|
||||
// (MonotonicGate — a slow older completion must never overwrite a newer LatestFrame).
|
||||
private static readonly TimeSpan MinConvertInterval = TimeSpan.FromMilliseconds(10);
|
||||
/// <summary>TASK 33: the "shed our own load first" cadence — 30 conversions/s instead of ~100.
|
||||
/// The viewer's tier does not change; only how often we pay for a readback.</summary>
|
||||
private static readonly TimeSpan ShedConvertInterval = TimeSpan.FromMilliseconds(33);
|
||||
private static readonly TimeSpan TelemetryInterval = TimeSpan.FromSeconds(2);
|
||||
private const int MaxConcurrentConversions = 3;
|
||||
private const int PoolBufferCount = 5;
|
||||
private DateTime _lastConvertAt = DateTime.MinValue;
|
||||
private TimeSpan _convertInterval = MinConvertInterval;
|
||||
private DateTime _telemetryFrom = DateTime.UtcNow;
|
||||
private DateTime _lastTelemetry = DateTime.UtcNow;
|
||||
private long _skippedCadence;
|
||||
@@ -79,6 +83,10 @@ public sealed class ScreenCaptureFrameSource : IScreenCaptureSource
|
||||
public string Key { get; }
|
||||
public event Action<VideoFrame>? FrameAvailable;
|
||||
|
||||
/// <summary>TASK 33: halve our own capture cost before asking the creator to accept a lower tier.
|
||||
/// Idempotent; the pump keeps its declared fps either way (it pads), so no output contract changes.</summary>
|
||||
public void ShedLoad(bool shed) => _convertInterval = shed ? ShedConvertInterval : MinConvertInterval;
|
||||
|
||||
internal ScreenCaptureFrameSource(string key, GraphicsCaptureItem item)
|
||||
{
|
||||
Key = key;
|
||||
@@ -171,7 +179,7 @@ public sealed class ScreenCaptureFrameSource : IScreenCaptureSource
|
||||
return;
|
||||
}
|
||||
var now = DateTime.UtcNow;
|
||||
if (now - _lastConvertAt < MinConvertInterval)
|
||||
if (now - _lastConvertAt < _convertInterval)
|
||||
{
|
||||
_skippedCadence++;
|
||||
frame.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user