VideoStream: improve RDPGFX flow control on impaired links
On high-latency, lossy, or jittery links, the RDPGFX send path can only submit a small number of frames before it has to wait for the client to acknowledge them. Keeping that limit fixed at two frames causes the stream to slow down as latency increases.
The source frame-rate setting stays simple, while latency handling moves to the RDPGFX submission window. The submission path tracks how many frames are already waiting for acknowledgement and sizes that limit based on the measured round-trip time (RTT).
The first two changes introduce the behavioral change that fixes the throughput collapse. The last two commits refine how the submission window is sized so it neither over-buffers nor reacts too strongly to short RTT spikes.
Change structure
-
Remove the RTT-based source-rate heuristic.
Remove
updateRequestedFrameRate()and its RTT callback. The stream no longer lowersrequestedFrameRatebased on RTT and decoded-frame delay. The source/encoder cap remains at the configured stream value. This commit only removes the FPS adjustment; the in-flight limit remains fixed at two frames. -
Size the in-flight frame limit from RTT.
Add
maxInFlightand updatehasInFlightCapacity()to use that value instead of the fixed constant.updateInFlightWindow()recomputes the limit wheneverNetworkDetectionreports a new RTT. The initial formula usesrequestedFrameRate * averageRTT, with a minimum of two frames and a maximum corresponding to one second of video.NetworkDetectionpublishes RTT values through atomics so they can be read safely from the submission path. -
Refine the window by using the frame rate received by the stream.
Add a producer-frame counter in the shared
queueFrame()path after a frame is accepted for streaming.effectiveProducerFps()estimates the rate of accepted frames, smooths it, and uses it instead ofrequestedFrameRatewhen sizingmaxInFlight. The estimate starts from the requested frame rate so the initial full-screen update gets a usable window immediately, then converges to the measured producer rate. -
Refine the window by smoothing the RTT used for the limit.
Add a second smoothing step for the RTT used by
updateInFlightWindow(). The code keeps the session's lowest validaverageRTT()as a floor, then uses a smoothed RTT value above that floor when calculatingmaxInFlight. This prevents brief RTT spikes from immediately increasing the in-flight limit while still allowing the window to grow enough to match the link characteristics.