After upgrading SDL2 from 2.0.22-2 to 2.24.0-1, get crackling noise when running Moonlight
I'm running Archlinux, and my problem occurs when I run Moonlight, which is a program that allows remote desktop access and is built using SDL2.
I performed a system upgrade today, and there were no updates to Moonlight, but there was an update to the SDL2 library. After the update, whenever I connect to another machine via Moonlight, all audio produced by my machine becomes very crackly, including audio produced by other apps. For example, I can have a Youtube video running in the background, and as long as Moonlight isn't connecting to another machine , the audio is fine. As soon as I connect to my remote desktop, the audio becomes crackly.
If I rollback the update to the SDL2 library, I am able to use Moonlight just fine with no audio distortion.
I'm not sure if this problem is specific to the way Moonlight is calling the SDL2 APIs. If you have other SDL2 demo audio programs you'd like me to test, I can try them. I was not able to reproduce the issue when using snes9x-gtk nor supertuxkart which I believe also use SDL2.
I'm able to reproduce the problem with the following program. Compiling and running this program causes audio in other apps (e.g. Youtube) to become distorted when SDL 2.24.0-1 is installed. There is no audio distortion if 2.0.22-2 is installed.
#include <SDL2/SDL.h>
#include <stdio.h>
int main(int argc, char* args[]) {
int initResult = SDL_Init(SDL_INIT_AUDIO);
if (initResult < 0) {
printf("SDL could not initialize: %s\n", SDL_GetError());
return -1;
}
SDL_AudioSpec want, have;
SDL_zero(want);
want.freq = 48000;
want.format = AUDIO_S16;
want.channels = 2;
want.samples = 240;
SDL_AudioDeviceID dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
printf("Waiting to continue...");
getchar();
SDL_Quit();
}
The issue seems to be related to the number of samples. If I change the want.samples = 240; to want.samples = 4096;, I don't hear any distortion.
Typically you don't go below 1024 samples because of this kind of issue (common to all audio drivers)
I'm surprised this is affecting other applications though. I'm guessing it's related to adding the flag PA_STREAM_ADJUST_LATENCY added in https://github.com/libsdl-org/SDL/commit/f6eb4b07593a3bb928ccf9d8569bf7a686159228. So we did two things, we removed doubling the buffer size, and added that flag, which sounds like it is affecting the latency for all audio sources on the system. @icculus, thoughts?
@cgutman, do you have logic to reduce the number of audio samples on PulseAudio because of the previous additional latency?
@cgutman, do you have logic to reduce the number of audio samples on PulseAudio because of the previous additional latency?
I don't. I've always just used the number of samples that each audio packet contains (240) and it's worked fine on Windows, macOS, and Linux up until this point. I'm using SDL_QueueAudio() so I can accumulate more samples than just 240.
Typically you don't go below 1024 samples because of this kind of issue (common to all audio drivers)
The docs for SDL_OpenAudioDevice say 512-8192 are generally good. I can easily change my code to use 512 or something, but the fact that applications can cause system-wide audio crackling by merely playing silence seems bad.
Arguably this is something PulseAudio should fix, but we can probably put a floor on the sample count to mitigate it for common cases like this.
Yeah, let's wait for feedback from @icculus. I suspect that PA_STREAM_ADJUST_LATENCY is a bigger hammer than we want in this case.
I assume this is a pulseaudio bug if we can break other processes, and 240 is an low number in general.
But I'll see if I can reproduce it here.
I could never reproduce it myself, but I realize now that was because I run Fedora which uses PipeWire instead of PulseAudio as the default audio daemon.
So the PA_STREAM_ADJUST_LATENCY flag has been there since SDL 1.2, arriving here:
https://github.com/libsdl-org/SDL-1.2/issues/458
...and SDL2 got it during SDL 1.3, when this was merged/reworked for the new audio interfaces.
So I'm hesitant to change this at this point, but let's hedge our bets by only setting the flag if the sample count isn't too low (say, if it's >= 512 samples)...this should fix the pathological case and otherwise make the code work the way it has for many years.
(Also, fwiw, the test case does not reproduce here, although I imagine it's hardware and driver specific.)
(But please let me know if the test case still causes problems for you with this change applied, and we'll reopen!)
I still think changing the global latency is a terrible idea - there may be other reasons why the global latency is set to a particular value.
BUT, this seems like a safe change overall.
@icculus, what other reason could an SDL update have suddenly triggered this? The original poster mentioned that rolling back SDL fixed the issue for them.
The original sample program in https://github.com/libsdl-org/SDL/issues/6121#issuecomment-1226877523 no longer reproduces for me, even when I revert my system back to 2.24.0-1. (That is, I'm able to watch a Youtube video while the program is running, and the audio sounds fine).
I'm guessing there's some interactions with other packages on my system, but I'm not able to figure out which. In particular, I'm unable to downgrade PulseAudio as doing so would break other packages I have on my system.
I still think changing the global latency is a terrible idea - there may be other reasons why the global latency is set to a particular value.
Part of the problem is that the docs say the default latency is set to two seconds, so we sort of have to do this, but also, the system shouldn't allow you to break other apps through this.
Since this issue vanished on the user's system, the only thing we should do here is maybe revert the patch I just made.
Yes, I think this was the only report of this, so let's go ahead and revert for now.
Reverted.