Repository navigation
Remote Play smoothness: ranked userland-only ideas #290
mauricio-gg
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary. A ranked list of 17 userland-only ideas for smoother PS5 Remote Play on the Vita, written in August 2026 when the PSN internet path was "the choppiest". Status today: 7 shipped (some in a different form), 1 partly shipped, 9 not done. The ones that moved the needle most were the thread and core layout (item 1), decoding on its own thread (item 11) and the PSN bitrate cap (item 3). The thread-priority reasoning in this post (why the feedback sender sits at priority 65 next to the AV threads at 64) is cited from a code comment in
lib/src/feedbacksender.c, so it is kept in full below.Platform facts the plan relied on
Checked against
main(0e9dd13) unless marked.vita/src/main.c:53-56: ARM 444, GPU 222, BUS 222, GPU crossbar 166). More needs a taiHEN kernel plugin and is out of scope.vita/src/config_values.c:18-29).target_bitratedown 5825k -> 2591k over 75 s). Do not over-report loss; reporting is post-FEC since PR fix(congestion): report post-FEC effective loss to stop PS5 bitrate ratchet (GH #206) #213.BitratePayload bitrate_changeintakion.protois a dev-overlay field no Remote Play client has got the PS5 to honour.holepunch.cis a NAT-rebound UDP probe, not a relay.SCE_NET_IP_TOSandSO_SNDBUF, but noSO_PRIORITY.videoreceiver.c:18-19(now:49-50), thatsceAvcdecDecoderan on the Takion receive thread (not since PR feat(video): decouple sceAvcdecDecode from Takion recv thread (GH #188) #199), and that the jitter ceiling was 100 ms (now 40 ms,lib/src/takion.c:85, PR fix(takion): break reorder-queue head-of-line deadlock on overflow #195).Why the feedback sender is at priority 65 (the part a code comment points here for)
Thread layout on
main, lower number = higher priority:lib/src/takion.c:1277-1278VitaDecode)vita/src/video.c:1330-1331vita/src/audio.c:207-208lib/src/feedbacksender.c:31, 413vita/include/host_input.h:11,vita/src/host_input.c:261-262The original bug (PR #242, merged 2026-08-11).
chiaki_thread_create()creates every library thread at the default Vita priority0x10000100, about 160 (lib/src/thread.c:71-72), and nothing promoted the feedback sender. The thread that puts every button press and stick movement on the wire was therefore the lowest-priority thread in the entire real-time input path, squeezed hardest exactly when decode and render load peak. It fit every symptom: input felt delayed but everything registered, sticks and buttons were affected equally (one shared thread), and video and audio were fine.Why 65 and not 64. Receive, decode and audio are each pinned to 64 on a different dedicated user core, so they never compete with each other. The Vita has only three usable user cores, and all three are already claimed, one each. A fourth thread also at 64 with no core of its own would timeslice against whichever of those three owns the core it lands on. The feedback sender wakes 80-170 times a second to do GKCrypt keystream generation plus a
sendto()that can block inside the Vita network stack, which is a real risk for decode and audio scheduling. Priority 65 still achieves the goal (far above input sampling's 96, vastly above the default ~160 that caused the bug) while guaranteeing it never ties with the three AV threads. For the same reason it gets no CPU affinity mask: there is no spare user core to dedicate, so it stays unrestricted, as input sampling already does.Ranked ideas and their status
Sizes: S under a day, M 2-5 days, L 1-2 weeks.
Tier 1: high return, low risk
SO_SNDBUFand a read-back log (S). Shipped, PR fix(net): SO_SNDBUF symmetric tuning + Senkusha 1ms RTT fallback fix #148 (lib/src/takion.c:384-402, 505-518).PSN_REMOTE_BITRATE_CAP_KBPS,vita/include/host_constants.h:5, applied atvita/src/host.c:201-208). The plan's opt-out config option was not built; it is a fixed constant.lib/src/session.c:723). The proposed 30 ms value for PSN paths is still a TODO in the code comment.lib/src/remote/holepunch.c:74), but it is a fixed value, not the proposed 30 s after the data connection is established.holepunch.c:95), original 250 elsewhere.Tier 2: high return, moderate effort
takion.c:69). Head-of-line blocking was instead addressed by the adaptive jitter buffer and PR fix(takion): break reorder-queue head-of-line deadlock on overflow #195 (reorder-queue deadlock fix).lib/src/audioreceiver.chas no jitter buffer.vita/src/video_overlay.c:162-190). Treat its "Latency" value with caution: it is the handshake RTT plus the control-channel EWMA, not a live round trip (see the #251 IDR-wait freeze thread). The metrics went to the log instead (PIPE/FPScarriesrssi=,vita/src/host_metrics.c:759).takion.c:1332-1336).VitaDecodethread; the decode-to-UI handoff viaframe_ready_for_displayis unchanged. It stops decode from blocking packet draining on the receive thread.vita/src. The project went the opposite way for the same freeze: submit damaged frames through the loss instead of flushing (PR fix(video): submit-through-loss — replace the ~1s IDR-wait freeze with motion (#251) #257, see the Video delivery is bursty: frame arrival gaps up to 706ms while the console renders on time — felt as input lag #251 thread).IP_TOS = 0xB8(DSCP EF) (S code, M to validate). Not done. NoIP_TOSuse inlib/orvita/. It still needs an over-the-air capture to learn whether the Wi-Fi firmware maps it to a WMM access category.Tier 3: speculative
frame_overwrite_countstill exists (vita/src/video.c:975). A twin-texture swap was added for a different purpose (the last-good-frame freeze, GH Display: snapshot_last_good_frame() memcpy costs 30.5ms of every 33ms frame #245,video.c:122-132).force_psn_holepunchglobal with a stream-scoped argument (S). Not done. It is still a one-shot flag consumed and cleared inhost_stream()(vita/src/host.c:219-225).Explicitly rejected (still true)
SO_PRIORITY: not exposed bysceNet.IP_TOSis the closest substitute (item 13).Bottlenecks inventory, in short
The plan's bottleneck list (A-P) mapped to the items above: shared CPU 0 (A, item 1), decode on the receive thread (B, item 11), per-packet malloc (C, item 10), single decoded-frame slot (D, item 15), no send-buffer tuning (E, item 2), no QoS marking (F, item 13), no SIMD FEC (G, item 14), PSN using the LAN bitrate (H, item 3), keepalive CPU (I, item 5), the 1 ms Senkusha fallback (J, item 4), no diagnostics surfaced (K, item 9), the fragile global flag (L, item 17), no per-stream AV reorder timeout (M, item 7), no audio jitter buffer (N, item 8), the render-wait stall before swap (O, never measured), and the 48-socket NAT burst (P, item 6; now 24).
Verifying any of these
Build with
./tools/build.sh --env testing, stream for ten minutes on LAN and then over PSN, and compareframe_overwrite_count, decode timing and the PIPE/* log lines before and after. Stress-test at the edge of Wi-Fi range. Usegrep -aon the logs.Source: docs/ai/REMOTE_PLAY_SMOOTHNESS_PLAN.md (deleted from the repo in #281; recoverable from git history at commit 0e9dd13)
All reactions