[PR #368] [MERGED] fix: add VBV buffer constraints and improve UDP streaming #427

Closed
opened 2026-10-15 13:00:29 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/games-on-whales/wolf/pull/368
Author: @Baz00k
Created: 3/13/2026
Status: ✅ Merged
Merged: 4/9/2026
Merged by: @ABeltramo

Base: stable ← Head: fix/streaming-improvements


📝 Commits (10+)

  • 68fc791 feat: implement Apollo-style batched UDP send for video streaming
  • 9f80199 feat: add packet pacing to prevent client buffer overflow
  • 0bf85cb fix: add VBV buffer constraints to prevent frame size spikes
  • 0157c58 refactor: move batched_send to src/core platform abstraction layer
  • ac5d357 fix: add config v7 with VBV encoder constraints and revert v3-v6
  • c0fc08a Committing clang-format changes
  • ed2b0aa chore: add comments explaining values
  • 9f373b6 feat: add env config for pacing
  • 5dacc0b feat: add migration to v7 config
  • 91ed52f refactor: consolidate config migrations

📊 Changes

15 files changed (+1170 additions, -79 deletions)

View changed files

📝 src/core/CMakeLists.txt (+2 -0)
➕ src/core/src/core/batched_send.hpp (+104 -0)
➕ src/core/src/platforms/linux/batched_send/batched_send.cpp (+233 -0)
➕ src/core/src/platforms/unknown/batched_send.cpp (+19 -0)
📝 src/moonlight-server/CMakeLists.txt (+1 -1)
📝 src/moonlight-server/gst-plugin/gstrtpmoonlightpay_video.cpp (+2 -2)
📝 src/moonlight-server/rtsp/commands.hpp (+4 -2)
📝 src/moonlight-server/state/configTOML.cpp (+20 -16)
📝 src/moonlight-server/state/default/config.include.toml (+15 -12)
➕ src/moonlight-server/state/default/config.v7.toml (+562 -0)
📝 src/moonlight-server/state/serialised_config.hpp (+1 -1)
📝 src/moonlight-server/streaming/streaming.cpp (+160 -43)
📝 tests/CMakeLists.txt (+2 -1)
📝 tests/assets/config.test.toml (+1 -1)
➕ tests/testBatchedSend.cpp (+44 -0)

📄 Description

Summary

Fix streaming instability on clients with limited receive buffers (e.g. Moonlight-TV on embedded devices) and Wolf ignoring client bitrate settings.
Changes in this PR allowed me to go from unstable 12mbit stream with significant packet loss to full, stable 35mbit on my TV. This should also stabilize streaming over Wi-Fi.

Root cause: Missing VBV (Video Buffering Verifier) buffer constraints on all hardware encoder pipelines. Without VBV, CBR mode allows individual frames — especially IDR frames and complex game scenes — to spike 2-5x the per-frame bitrate budget, overwhelming client receive buffers.

Most of this code is just reimplementation of what alredy exists in Sunshine/Apollo.

Changes

1. Apollo-style batched UDP send

  • Replace async single-packet async_send_to() calls with synchronous batched sends using sendmmsg()
  • Add platform abstraction layer (batched_send.hpp/cpp) with Linux implementation
  • Configure socket QoS and buffer sizes optimized for streaming workloads
  • Increase default video packet payload size to match Moonlight protocol spec

2. Packet pacing

  • Add rate-limited packet pacing for video UDP sends (80% of 1Gbps link speed)
  • Sub-millisecond sleep-based scheduling between send windows
  • Smooths out large frame bursts that would could otherwise overwhelm low-powered devices

3. VBV buffer constraints for all encoders

  • NVIDIA (nvcodec): Add vbv-buffer-size to all nvh265enc, nvh264enc, nvav1enc pipelines (config v3-v6 + include)
  • VAAPI (va): Fix rate-control from cqp (Constant QP — ignores bitrate entirely) to cbr, and fix cpb-size from {bitrate} (1-second buffer) to single-frame buffer
  • VBV buffer size computed as bitrate_kbps / refreshRate (one frame's worth), matching Sunshine/Apollo's approach

Fixes #332

Testing

Tested on Moonlight-TV at 35 Mbps AV1 with stable streaming (previously broke above 12 Mbps).
Streaming still works on original Moonlight and Artemis clients (tested on S23 Ultra and M1 Mac).

Files Changed

  • streaming/streaming.cpp — Batched send, pacing, VBV format arg
  • platform/batched_send.{hpp,cpp} — New batched send abstraction
  • platform/linux/batched_send.cpp — Linux sendmmsg implementation
  • gstrtpmoonlightpay_video.cpp, rtsp/commands.hpp — Packet size
  • config.include.toml, config.v3-v6.toml — Encoder pipeline fixes

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/games-on-whales/wolf/pull/368 **Author:** [@Baz00k](https://github.com/Baz00k) **Created:** 3/13/2026 **Status:** ✅ Merged **Merged:** 4/9/2026 **Merged by:** [@ABeltramo](https://github.com/ABeltramo) **Base:** `stable` ← **Head:** `fix/streaming-improvements` --- ### 📝 Commits (10+) - [`68fc791`](https://github.com/games-on-whales/wolf/commit/68fc79177bd19ed2afe85cfba76c1fc887ef93d9) feat: implement Apollo-style batched UDP send for video streaming - [`9f80199`](https://github.com/games-on-whales/wolf/commit/9f80199dc2d72c3b4618ca84b1bb93725bd91b7c) feat: add packet pacing to prevent client buffer overflow - [`0bf85cb`](https://github.com/games-on-whales/wolf/commit/0bf85cb92c5a4025bd6b0cc53dac7b4ee71a70ba) fix: add VBV buffer constraints to prevent frame size spikes - [`0157c58`](https://github.com/games-on-whales/wolf/commit/0157c5821208040be8c3225441997b475f2be7c8) refactor: move batched_send to src/core platform abstraction layer - [`ac5d357`](https://github.com/games-on-whales/wolf/commit/ac5d3578ab6041d4cd086075f41f383d4450248d) fix: add config v7 with VBV encoder constraints and revert v3-v6 - [`c0fc08a`](https://github.com/games-on-whales/wolf/commit/c0fc08a7c5d6ec110b5fd5fbf925707361d13945) Committing clang-format changes - [`ed2b0aa`](https://github.com/games-on-whales/wolf/commit/ed2b0aa5bfbda738b7539e435b0e49289318dd3b) chore: add comments explaining values - [`9f373b6`](https://github.com/games-on-whales/wolf/commit/9f373b60c3d01ee39b3f7fd7d81b01bba6c59f8f) feat: add env config for pacing - [`5dacc0b`](https://github.com/games-on-whales/wolf/commit/5dacc0bcdd06b1aee25b3a94370ee4b81c9887df) feat: add migration to v7 config - [`91ed52f`](https://github.com/games-on-whales/wolf/commit/91ed52f49efe0e72c26266b7c9cc01979f58005a) refactor: consolidate config migrations ### 📊 Changes **15 files changed** (+1170 additions, -79 deletions) <details> <summary>View changed files</summary> 📝 `src/core/CMakeLists.txt` (+2 -0) ➕ `src/core/src/core/batched_send.hpp` (+104 -0) ➕ `src/core/src/platforms/linux/batched_send/batched_send.cpp` (+233 -0) ➕ `src/core/src/platforms/unknown/batched_send.cpp` (+19 -0) 📝 `src/moonlight-server/CMakeLists.txt` (+1 -1) 📝 `src/moonlight-server/gst-plugin/gstrtpmoonlightpay_video.cpp` (+2 -2) 📝 `src/moonlight-server/rtsp/commands.hpp` (+4 -2) 📝 `src/moonlight-server/state/configTOML.cpp` (+20 -16) 📝 `src/moonlight-server/state/default/config.include.toml` (+15 -12) ➕ `src/moonlight-server/state/default/config.v7.toml` (+562 -0) 📝 `src/moonlight-server/state/serialised_config.hpp` (+1 -1) 📝 `src/moonlight-server/streaming/streaming.cpp` (+160 -43) 📝 `tests/CMakeLists.txt` (+2 -1) 📝 `tests/assets/config.test.toml` (+1 -1) ➕ `tests/testBatchedSend.cpp` (+44 -0) </details> ### 📄 Description ## Summary Fix streaming instability on clients with limited receive buffers (e.g. Moonlight-TV on embedded devices) and Wolf ignoring client bitrate settings. Changes in this PR allowed me to go from unstable 12mbit stream with significant packet loss to full, stable 35mbit on my TV. This should also stabilize streaming over Wi-Fi. **Root cause**: Missing VBV (Video Buffering Verifier) buffer constraints on all hardware encoder pipelines. Without VBV, CBR mode allows individual frames — especially IDR frames and complex game scenes — to spike 2-5x the per-frame bitrate budget, overwhelming client receive buffers. Most of this code is just reimplementation of what alredy exists in Sunshine/Apollo. ## Changes ### 1. Apollo-style batched UDP send - Replace async single-packet `async_send_to()` calls with synchronous batched sends using `sendmmsg()` - Add platform abstraction layer (`batched_send.hpp/cpp`) with Linux implementation - Configure socket QoS and buffer sizes optimized for streaming workloads - Increase default video packet payload size to match Moonlight protocol spec ### 2. Packet pacing - Add rate-limited packet pacing for video UDP sends (80% of 1Gbps link speed) - Sub-millisecond sleep-based scheduling between send windows - Smooths out large frame bursts that would could otherwise overwhelm low-powered devices ### 3. VBV buffer constraints for all encoders - **NVIDIA (nvcodec)**: Add `vbv-buffer-size` to all `nvh265enc`, `nvh264enc`, `nvav1enc` pipelines (config v3-v6 + include) - **VAAPI (va)**: Fix `rate-control` from `cqp` (Constant QP — ignores bitrate entirely) to `cbr`, and fix `cpb-size` from `{bitrate}` (1-second buffer) to single-frame buffer - VBV buffer size computed as `bitrate_kbps / refreshRate` (one frame's worth), matching Sunshine/Apollo's approach ## Related issues Fixes #332 ## Testing Tested on Moonlight-TV at 35 Mbps AV1 with stable streaming (previously broke above 12 Mbps). Streaming still works on original Moonlight and Artemis clients (tested on S23 Ultra and M1 Mac). ## Files Changed - `streaming/streaming.cpp` — Batched send, pacing, VBV format arg - `platform/batched_send.{hpp,cpp}` — New batched send abstraction - `platform/linux/batched_send.cpp` — Linux sendmmsg implementation - `gstrtpmoonlightpay_video.cpp`, `rtsp/commands.hpp` — Packet size - `config.include.toml`, `config.v3-v6.toml` — Encoder pipeline fixes --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-15 13:00:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/wolf#427
No description provided.