r/MoonlightStreaming • • 17h ago

Introducing Starwire 0.1.0 - A Comprehensive Android Moonlight Client Solution

78 Upvotes

Hey everyone! I have been exclusively streaming games from my headless PC to cloud devices for about five years now. I recently found myself looking for a new Android client, and came upon u/MoreOrLessCorrect's Moonlight X, which includes direct frame pacing and PyroWave support. It had a noticeable impact on my stream quality, even without using PyroWave (I don't have the connection strength to use it in practice), but I wondered how the stream could perform if it had the Fast V-Sync, LFR, Async, and Codec options that Artemis/Artemide has. I also missed some QoL features that the recent Windows forks have adapted that seem to be lagging in terms of an Android client equivalent.

Back-end development started from Moonlight X's fast video pipeline, adds the touchscreen tools from Artemide and Artemis, and picks up favourite features from Moonlight V+, Moonlit Artemis and Moonlight X Turnip. I then gave it a refreshed UI that draws from some of the trends coming out of Silicon Valley these days. It installs next to any Moonlight you already have, so you can try it without giving anything up.

⬇ Download Starwire · GitHub

The whole screen picks up the colour of whatever you select. Games show their own cover art; apps like Desktop or Steam Big Picture get their own icons.

Features & Value Proposition

🎨 A look that follows your game: The screens take their colour from the game you've picked, and apps without cover art get their own icons. Your last game is ready to go with one tap, with its stream settings right under its name.

🎮 Everything during a stream, one tap away: Open the menu with the floating button, a three-finger tap or by holding Select on a controller. Keyboard, full on-screen keyboard, mouse modes, zoom, key shortcuts, monitor switching, bitrate, clipboard: it's all in one grid, and works with a controller too.

The new in-stream menu over Aniimo. Game screenshot © Pawprint Studio, from its Steam page.

⚡ Fast and smooth: A Vulkan renderer, the PyroWave codec, and low-latency options like Warp Drive, Fast V-Sync and async decoding for when every millisecond counts.

🧭 Feature-packed and intuitive settings: Sections with plain names (Stream, Sound & vibration, Controllers…), and a Predicted impact panel that shows whether your choices lean towards fastest response or smoothest motion, and which setting is pushing it which way. Tap a setting that came from another fork and a small line under the panel says where it came from and who made it.

Redesigned Settings, with the Predicted impact panel on the right.

🖐 Made for touchscreens: Pinch to zoom anytime, trackpad modes, long-press to right-click, an on-screen keyboard with every key, and the option to hide the PC's mouse pointer while you play.

📳 Feel the bass: Audio haptics turns a game's bass into vibration on your device or controller.

Get started

  1. Set up your PC. I use Vibepollo; it enables every feature. Apollo works too, and Sunshine works for everything except a few extras (clipboard sharing, PC commands, Virtual Display and changing the bitrate mid-stream).
  2. Install Starwire. Download Starwire-0.1.0.apk from the release page and open it.
  3. Pair. Tap your PC, then type the PIN Starwire shows into your host's PIN page (usually https://localhost:47990). You only do this once.
  4. Play. Tap a game, then Play.

Android 5.0+. PyroWave and the custom Turnip driver need a 64-bit ARM device. Updates from the releases page install over the top and keep your settings, and Obtainium can keep it updated for you.

Development

I made Starwire as a vibecoding exercise after experiencing the wonderful software that is Vibepollo. I decided what the app should do and how it should look, and Claude Code wrote the code. I also used REA by morluto to look inside the other apps and see how their features work. Every feature is tested on my RedMagic Astra with a GameSir G8+ before it goes in.

Changelog

2026/10/22: Version 0.1.2 has been released, and fixes an error that caused the client to crash upon loading the list of apps due to an attempt to tint the Android device screen without sufficient permissions. To update, download the new APK and open it on your device. You will recieve a prompt to update the existing app, which will retain existing settings. Obtainium users should recieve the update automatically. Please keep the feedback coming!

Credits

Anything that came from another Moonlight version is that author's work. Please go give their repos a star:

  • Moonlight Android: Cameron Gutman and contributors, the original client
  • Moonlight X: MoreOrLessSoftware, the base of Starwire (Vulkan renderer, PyroWave, overlay menu, per-app settings, Quick Launch)
  • Artemis: Yukino Song (ClassicOldSong), pan/zoom, touch modes, clipboard, server commands, Virtual Display, Warp pacing, floating button
  • Artemide: derflacco, Fast V-Sync (Nano Pacer), Sync and Async LFR, async decode, MediaTek low-latency work, and the version of the Artemis features Starwire ported
  • Axixi2233's Moonlight fork: the full keyboard, shortcuts list, Lite overlay and shortcut file format (via Artemis)
  • Moonlight X Turnip: ncpt (NoCrypt), the custom Turnip Vulkan driver for PyroWave
  • Moonlight V+: qiin2333, ideas for changing bitrate mid-stream, audio haptics and 1% lows
  • Moonlit Artemis: Mohammad Forhad (4had45), ideas for the monitor switcher and pinch to zoom anytime
  • PyroWave: Hans-Kristian Arntzen (Themaister) · libadrenotools: Billy Laws (bylaws)
  • Vibepollo: Chase Payne (Nonary), built on Apollo (ClassicOldSong) and Sunshine (LizardByte)

The README lists every feature and whether it was ported (and from whom) or written new. If I've credited something wrongly or missed you, please let me know.

Bug reports and ideas are very welcome, here or as a GitHub issue. Built on GPL-3.0.


r/MoonlightStreaming • • 2h ago

What I learned getting full 4:4:4, Sliced Encoding, D3D12 capture, VRR and the last bit of latency out of AMD's encoder

36 Upvotes

Long and very technical read. Be warned.

I work as a platform engineer for over 15 years now and i have a quirk for optimizing the shit out of things.

So for a while now I've been researching one question: how good can game streaming get on a Radeon if you build the host around AMD's hardware instead of treating it as the third vendor for a fork of NVIDIAS gamestream?

The research is done through Rubylight, an AMD-only host for Moonlight that only cares about optimizations around AMD. It isn't another fork with a new name on it and a fancy sloppy ui that can do all the fancy features but still has 60 hz clients or cheats metrics or something. It does just well enough in the feature part that it reaches a small userbase contributing to feedback on bugs and issues. It's research on AMD, and what we learn goes back where it helps.

We contribute to Vibepollo, and I've asked Nonary about working together more closely.

Here's what the research turned up so far. All numbers are from flagship amd graphic cards. And what changes my work from slop is that most of this here wont change the numbers on your measurements and I dont put some fancy ui in and call it a day.

Every host measures "host processing" its own way, so I measure picture age instead: the test source draws a timestamp barcode into every frame, and an independent receiver reads it back after decoding. That's the time from the moment a picture is rendered to the moment the client has it decoded. It's the same yardstick for every host and you can't game it from the host side.

4:4:4 on an encoder that can't do it

AMD's hardware encoders only do 4:2:0, and AMD's own AMF docs say so for every VCN generation up to 5.0. There are two ways around that.

The first is PyroWave, Themaister's wavelet codec. It runs as Vulkan compute, skips VCN entirely and does full 4:4:4 up to 10-bit HDR. What made it fast under load was moving the RGB to YUV conversion off the graphics queue. With a game running, the conversion sat behind the game's draws and took 5.6 ms a frame. As one compute shader on a high-priority D3D12 compute queue, writing straight into the textures Vulkan imports, it takes 0.55 ms. This number does not show up in any metric in moonlight but will greatly impact glass to glass latency.

The second is packing, which keeps the normal HEVC and AV1 hardware encoders. A 4:4:4 frame has exactly as many samples as a 4:2:0 frame twice as tall. So Y goes in the top half of the luma plane, the odd columns of Cb and Cr sit side by side in the bottom half, and the even columns fill the chroma planes. The encoder sees an ordinary double-height picture, the client decodes it with its ordinary hardware decoder, and a shader puts every sample back exactly where it came from. HEVC and AV1, 8 and 10-bit, all reach about 1440p120 this way, even on a Radeon 780M.

The third is predictive packing for the 10-bit modes. Here the top half of the picture is a normal 4:2:0 frame. The chroma samples 4:2:0 would throw away fill the rest, stored as halved differences from the sample they share a 2×2 block with. On most content those differences are small, so that part of the picture sits near flat grey and costs few bits. Halving costs at most one code value before compression and keeps the encoder's rounding from wrapping a difference around.

Both packed modes are opt-in, since stock Moonlight would just show you the packed picture. Nightjar, our client, unpacks both.

Fenced D3D12 capture

On a virtual display the host doesn't use WGC or Desktop Duplication at all. Our driver copies every frame Windows composes for its monitor into a ring of textures it shares with the host, stamps the present time next to it and signals the host. That ring used to hand textures back and forth with keyed mutexes. Now its textures and fences live on the GPU's D3D12 compute device. The driver signals a "written" fence after its copy, the conversion shader reads the texture in place after waiting on that fence on the GPU, and the compute queue signals a "released" fence when it's done so the driver can reuse the slot. The wait happens on the GPU instead of a CPU thread, and no D3D11 work runs for it.

Claiming a frame went from about 32 µs with the keyed mutex to 1.8 µs. Under GPU load at 1440p120 HEVC, every fence run held a full 120 fresh pictures a second, p99 picture age dropped from 19.3 to 18.1 ms in SDR and from 21.3 to 19.4 ms in HDR, and the p99 frame interval in SDR went from 13.8 to 11.2 ms. That's picture age from the game's render through decode, about 14 ms on average with the GPU busy.

Under load Keyed mutex Fence
Fresh pictures/s, SDR / HDR 120.0 / 119.7 120.0 / 120.0
Picture age p99, SDR 19.3 ms 18.1 ms
Picture age p99, HDR 21.3 ms 19.4 ms
Frame interval p99, SDR 13.8 ms 11.2 ms

These numbers don't look huge, but mind you we are looking at optimization wherever possible, so they were for me.

Slices

Moonlight asks the host for slices, and I wanted to know what they buy on AMD. I did 630 encoder runs across HEVC and AV1, 1080p up to 7680×2160, 60 to 240 fps, with split-frame encoding forced on, forced off and left alone, then again with 2 and 4 slices. Every variant encoded in the same time, within 0.2 ms. The driver reports two encoder engines, but one stream uses one engine, and slices don't change that.

Where slices can pay off is getting out of the encoder early. AMF can hand back each slice as soon as it's encoded, so you could packetize and send the top of the frame while the bottom is still encoding. That's what I'm testing next. So far its promising if the client supports it. Again that is why I had to also develop a client framework in a language I understand to fully be able to test this and why its so important for me to have my own client/host.

VRR

Thanks to Nonarys findings, the virtual display driver goes up to 1000 Hz, so when the client asks for VRR the desktop doesn't cap the game's present rate. Here's what we do differently to reach more smooth VRR:

  1. Rate cap. The host takes each frame as soon as it arrives, but never faster than the stream rate the client asked for. Repeated frames count toward that rate; a frame re-encoded because the client lost packets doesn't. Without the cap, a game running faster than the stream on a 1000 Hz display left every frame short of bits: blurry picture, fringed text, flooded link.
  2. Pacing instead of tiny queues. Vibepollo's VRR mode shrinks its queues (WGC frame pool from 2 to 1, low-latency AMF input queue). We keep the queues and change the pacing: predictive waits off, frames can be claimed half a frame period apart instead of three quarters, WGC's slot-aligned publishing off, refresh lock off since a VRR display follows each frame anyway. The encoder holds at most two frames on every stream, VRR or not.
  3. Extra WGC compositions. When Windows publishes more compositions than the game produces, the host lines up with the game's real updates. On a 60 fps source that's 57.7 against 59.9-60 fresh pictures a second.
  4. Our own display driver. Capture comes straight from it in about 0.2 ms, HDR included.
  5. Presenting on the client. Nightjar schedules VRR frames from the host's timestamps without needing a shared clock. A clock-sync message adds latency measurement on top.

Radeon controls in alpha.2

Change AMD Controls like Anti-Lag, Chill, Boost, RIS, the frame cap or AFMF from the couch and get your own settings back afterwards. A probe round-trips every ADLX 3D setting on the installed driver, and only the ones that really write get exposed: 24 with AMD Software 26.9.2. Your original values go into a journal on disk before anything changes, and they're put back when the session ends or the game closes, or at the next start if the host crashed. If you changed a setting on the PC in the meantime, it's left alone. Its a feature that just makes sense. Most of the time, tops having this natively.

Background Streaming

My Children play on my rig while I work at the same time. I use Rubylight and Hyper-V AMD GPU-PV to a VM with Rubylight to isolate input and the game. Works well enough for kids to not notice. https://github.com/RamazanKara/Rubylight/blob/main/docs/configuration.md#background-streaming-from-a-hyper-v-vm

Where the latency goes

At 1080p60 the host stages are capture 0.22 ms through our display driver, conversion 0.26 ms, HEVC encode 2.43 ms and packetizing 0.03 ms. Nearly all of it is the encode. We are looking at microseconds now to find any further optimizations.

The bigger wins came under load:

  • Frame prep on the compute queue took average picture age from 41.0 to 33.5 ms with the GPU busy.
  • Keeping at most two frames in the encoder took present-to-send from 42.7 to 11.1 ms when the encoder was saturated.
  • Giving controllers their own input thread took a mouse move stuck behind a controller update, under full CPU load, from 287 ms to 2 ms.
  • approximately 5000 different tests has been done on various AMD quirks and metrics. These led to countless small improvements you can read about in the docs.

Benchmarks

We do not measure AMD with Rubylight against other Sunshine Forks anymore, because the glass-to-glass latency under load is so far ahead that it is just not worth the time. If you want, you can still compare it yourselves. Rubylights test setup is available and there are historic measurements available.

The full measurement record, with methods and every run, is public: PERFORMANCE.md. Questions are welcome, and if you have AMD numbers that disagree with mine, I want to see them. For anybody stable should use vibepollo and wait till that research has been backported. For anyone wanting to contribute test out rubylight 3.0 + nightjar and give feedback in form of issues with logs and so on, please just dont bodly claim host x has better latency under load just from the host processing number, I do not care about that.


r/MoonlightStreaming • • 21h ago

Using Apollo+Artemis, I can't set the Virtual Display as the main display and turn off the main physical display

Thumbnail
gallery
3 Upvotes

"Make this my main display" option is greyed out for the virtual display and I believe it should appear on NVIDIA control panel too right? but it's not. it appears on Device Manager though. I just want to be able to stream on my phone and have the main monitor of my PC turned off but I can't seem to get it working using the usual steps like manually setting the virtual display as main in Windows settings. headless mode also doesn't do anything for me.


r/MoonlightStreaming • • 29m ago

unstable connection

• Upvotes

Hi,

I've been running Moonlight for a month now without any issue, today out of a sudden, I'm getting unstable connection message and the screen is stuck, only thing I remember i did was unplug my TV by accident and plugged it in again, do I need to configure my Apollo client again? did passphrase or IP address changed by unplugging my tv?

I tried restarting my PC and my TV but same issue.

I'm streaming to my LG TV WebOS


r/MoonlightStreaming • • 1h ago

iPad as second monitor on GNOME Wayland (hotswappable, no dummy plug with KMS capture)

• Upvotes

This all started because I couldn't get xdg portal to work, it would always habg up as soon as I tried connecting (so being able to create virtual displays wasn't useful bc I wouldn't be able to stream them.)

This uses KMS

My school's wifi network is super saturated but it's still useable for text, especially since it's using full native resolution. I'm waiting on an adapter to do this via a wired ethernet connection tol (I already did it with a secondary wifi card on a private network so it should definitely work)
I used kernel debugging to assign a custom edid to an unused didplay connector (the one for the internal display, since it's broken.) This method is hot-swappable and didn't require a reboot to setup (nor to undo.) I will test it out with KDE next, I don't see why it shouldn't work (didn't use anything mutter-specific)
Note: I haven't been able to get hardware-accelerated encoding working, using software encoding right now.


r/MoonlightStreaming • • 5h ago

Super weird host processing latency on Witcher 3 remastered only

2 Upvotes

I am having this really weird behavior where when streaming from my 5090 pc to my steam machine or steam deck over Ethernet, sometimes it's flawless for hours and I can play just fine, but more often it's got host processing latency maximums at 500ms or more and it's unplayable.

If I restart my pc 5x sometimes it works and I can play, in others it's the same result.

If in that exact same session where I am getting 500ms, I just close the game and open another, control resonant for example, it is flawless and plays with 5ms max. Which says to me it's something with how the game interacts with my virtual IDD monitor perhaps and gamestreaming.

I have tried disabling full screen optimizations, borderless and full screen, no luck. Not really sure what else to do.

Any ideas? AI hasn't been helpful.


r/MoonlightStreaming • • 6h ago

Legion go 2 - primary use moonlight. Steam Os or Windows?

2 Upvotes

For those that use it for moonlight is it best to have it on windows or steam for moonlight?


r/MoonlightStreaming • • 4h ago

Hybrid gyro mode for Dish: I vibe coded some fixes for DISH android

1 Upvotes

Hi everyone, Using just GPT I made some fixes for DISH one of them was just adding the way to choose wich landscape mode you want a Hybrid Gyro mode in case you are using a GamesirX5lite like me and want a full DS4 emulation using the phone gyro. So Here it is. DishHybrid: Souly Edition.

https://github.com/CapolinerSoul/dish-android/releases/tag/v0.1.0-souly-preview.1

have little experience with github and stuff And I hope this gets added to the main app

Just made a name and Icon so it wont intefere with your previous Dish installs.


r/MoonlightStreaming • • 13h ago

Can I align them to not overlap and utilise vertical tabet screen as above display below keyboard (apollo+Artemis)

Post image
1 Upvotes

r/MoonlightStreaming • • 20h ago

Can't figure out why sporadic stutters happen while streaming to android client

1 Upvotes

So for context, my host machine is CachyOS:

CPU: 7700x3D

GPU: RTX 5080

RAM: 32GB

The host is wired and the speeds are the following:

Download: 1 Gbps

Upload: 36~38 Mbps

This is really the best my area offers unfortunately (my area only has Spectrum).

Now I have tried a variety of hosts services and I always experience the same thing: on average for every 10 or 20 minutes, for about 4~6 seconds, there is a chance the stream starts stuttering as both the frames drop and so does the audio, which then restores just fine. When it doesn't happen, it runs really smoothly. I have noticed this is independent of the resolution I am streaming it at. This happened before even when on AMD (previously an RX 7600XT).

The services I have tried thus far are: Sunshine, Polaris, and currently Punktfunk. Punktfunk has been the easiest to set up for virtual screens and turning the monitor off automatically when starting the stream to a connected client which is why I am on it right now. Otherwise, I have noticed the performance is the same across all of them and the issue persists regardless of it.

I honestly have no clue what could be the culprit in this case. Is it the firewall? My home server's pihole (although this would happen prior to running pihole as well so I doubt it). Is it the clients themselves (I've only tested with the android Moonlight client and the android Punktfunk client)? It really does demoralize me since it is otherwise a really great experience and I have been playing more games this way too but those stutters drive me insane, especially during critical moments such as a cutscene you can't pause in game.

Any help or direction to help would be appreciated.


r/MoonlightStreaming • • 22h ago

Virtualhere + DS5dongle

1 Upvotes

This isnt technicslly a Moonlight issue but I didnt know where else to ask and I'm sure this is a common use case. I'm not sure if anyone is using this but I've been trying this setup because I'm using an Xbox Series S as a client and I want to game with a PS5 controller but have had nothing but problems.

DS5dongle works fine normally but coupled with Virtualhere it constantly comes disconnected and the rumble is desynced. I'm using a Raspberry Pi4 as a USB server, is it possible maybe its not supplying enough power to the dongle? I would test but I dont want to buy a license to use it on a different machine.


r/MoonlightStreaming • • 23h ago

Onexplayer 3 Stuttering every 10mins on Moonlight Streaming

Thumbnail
1 Upvotes

r/MoonlightStreaming • • 10h ago

Calling All Beta Testers: LuminalShine 26.10.0-beta.1 has Arrived

0 Upvotes

Calling all beta testers! LuminalShine 26.10.0-beta.1 has been released for testing, featuring a plethora of new features.

What does this Release Include?

  • Pyrowave Support (NOTE: PyroWave defaults to 700Mbps as it was tested on 10G Host to WiFi 6E at 4K@120Hz - if you experience issues, 500Mbps is recommended)
  • Borealis (Android Client) LuminalShine features Support added thanks to contributor magalz who also corrected server host responses to recognize the installed host application is LuminalShime.
  • All windows will now be displayed on the virtual monitor using the virtual monitor's GUID while streaming
  • Mission Control WebUI now allows the importing of apps.json files so they are no longer overwritten by LuminalShine's protection mechanism
  • LuminalShine is now prepared to use Nonary's new controller driver, allowing for the removal of ViGEmBus.

Full Changelog: https://luminalshine.feedback.northebridge.com/changelog

Download LuminalShine 26.10.0-beta.1: https://github.com/NortheBridge/luminalshine/releases/tag/26.10.0-beta.1