-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Distorted audio with moonlight-qt and sdl2-compat on Arch Linux #329
Comments
Can you please note the versions of SDL and sdl2-compat you're using? |
I'm running Arch Linux with kernel 6.13.1, Gnome on Wayland. Package versions:
|
Thanks, we'll take a look! |
Interesting, I was actually just running this test with the exact same configuration (Arch Linux client too) and audio was okay outputing to an HDMI audio device (monitor). When you start a stream Moonlight will print some message about the audio configuration which look like:
Can you post those from your test? |
In my case its:
To be 100% sure it's
|
Setting the audio driver to
Note that I also tested downgrade to regular |
What happens if you set the environment variable |
That works; audiodriver is mentioned as being |
@icculus, we should fix whatever bug we have when the SDL2 app sample count doesn't match the actual sample count, but then I think we should have sdl2-compat set SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES to the application spec sample count when opening an audio device, so we get as close a match as possible. |
Ok, I think the correct fix is to set the hint, but I don't think there's any other bug to be fixed in our code. From here, it looks like Moonlight is flying too close to the sun in their audio queueing and it happened to work out in SDL2: Forcing the hint will probably give them enough buffer to not have underruns, and that's all we can do here. |
Is there a way that we can see which audio buffer size that we picked in the PipeWire backend? The fact that a 15 ms buffer works for WASAPI, PulseAudio, and ALSA, but not PipeWire (and it did work for PipeWire in SDL2) makes me wonder if there is something we can do to improve SDL3's behavior here. (As an aside, it would be wonderful to get an underrun notification from SDL so I can detect this is happening and adjust how much audio I'm buffering) |
Downgrading to 2.30.51 fixed it for me, higher version gives crackling audio, looks like it's something since 2.30.52 |
So there are only 3 audio-related commits between .51 and .52, but one of them is a doozy.
I'm guessing that it's worth testing Moonlight with the latest in revision control but b2d2190 reverted, which just requires commenting out one line, if @mdmatthias is able to try this. My current guess is that Moonlight is asking for a too-small hardware buffer, and SDL2 is refusing to do it, instead giving it a larger one. On top of that, it's looping until there are almost no samples left in the audio queue, which works when the hardware is buffering more behind the scenes but is leading to tons of underruns when it isn't. Another theory: SDL_GetQueuedAudioSize() reports bytes in the queue...in SDL2, this is converted bytes, but in SDL3 this is data that has not yet been converted...so I'm wondering if this code is blocking for 300 milliseconds every time because sdl2-compat is returning the SDL3 value at the moment. |
Also, @cgutman, are you the Moonlight maintainer? If so: In that code I linked to, is there any value in waiting for the queue to be almost drained before queueing more? In that function, you already know you have X more bytes to queue, why not just queue it and let the system sip from the queue as necessary? |
Moonlight is already passing
It's looping until there are 10 frames of audio (50 ms) or less of unconsumed audio data queued to the SDL audio stream, which is over 3x more than the buffer size we asked for in I'm not totally convinced that it's due to getting a pipewire buffer that's too small. I'm wondering if it's actually due to getting a buffer that's too large instead. For example, if the underlying PW audio buffer was 100 ms, then the code there would constantly flap between having >= 100 ms and having 0 ms queued and playing (at least) half a buffer that's padded with silence because the queuing logic will refuse to queue more than 50 ms at a time. I think the fundamental assumption I made there is that the audio device will consume data from the stream in multiples of the
That's certainly an interesting theory (and at least a good bug to fix). Moonlight is calculating the duration of queued audio by using the sample size of the audio stream it opened, so that could definitely cause issues if it's returning an incorrect value there.
The reason for all that complicated queuing and waiting logic there is that I'm trying to constrain the amount of audio data that can be queued to the audio device in order to prevent latency from building up in the audio playback pipeline. With an inconsistent network connection, audio packets from the host PC can be delayed (or dropped and later recovered via FEC packets) and subsequently arrive after they're supposed to have been played (this can also happen if the playback device is temporarily paused due to a default device switch or whatever). Some amount of late audio traffic needs to be accepted in order to smooth over network jitter without running dry, but we don't want to let it accumulate forever. The code there is attempting to keep some data in all queues to avoid underruns but not too much that it creates significant audio latency for the user. |
FWIW, Steam Link does something very similar, but is already using SDL3. |
I think I understand the issue now but it's not clear what the best way to fix it is. I went back to 9110cc1 to investigate (since that commit does exhibit the issue for me, unlike the current code now). I found that it's not that the audio buffer underruns, it's that SDL3 is taking whatever the app can provide immediately and then padding the rest of the buffer with silence. Without the app being able to influence the size of those audio buffers (like SDL2 could via The problem with the code in 9110cc1 was that it would not fully populate the provided buffer up to This same phenomenon is reproducible with SDL3 natively too using some testcode based on the modified repro provided for #311 SDL3 test code
When running out of the box without I took a look at the audio drivers in SDL3 and some of them (PipeWire included) can theoretically handle partially filled buffers and do the right thing. However, a bunch of them also have assumptions that the buffers returned will always be completely populated. Some of them would need significant rework to support providing partially filled buffers (if they can support it at all). Maybe for now the best thing to do is to have sdl2-compat set |
I'm running Arch Linux. I use
moonlight-qt
to stream my desktop (which runssunshine
) to my laptop (all systems running Arch Linux).Since the upgrade of
sdl3
and introduction ofsdl2-compat
, I have highly distorted audio. It is specifically not due to network latency, which sounds very different. This sounds like way too loud oversteering or clipping, robotic. It sounds similar to libsdl-org/SDL#12150.I've made a video to illustrate the issue (zipped, because I can apparently not upload an mp4 directly):
moonlight-qt-sdl2-compat-distorted-audio.zip
The text was updated successfully, but these errors were encountered: