[PATCH 0/1] MR10792: winepulse.drv: Don't advance read pointer past data not yet consumed by PA
Adds a simple throttling mechanism to prevent pointer overlaps when winepulse is faster than the audio server. Winepulse uses a fake clock to advance the pointers: ```c /* regardless of what PA does, advance one period */ adv_bytes = min(stream->period_bytes, stream->held_bytes); stream->lcl_offs_bytes += adv_bytes; stream->lcl_offs_bytes %= stream->real_bufsize_bytes; stream->held_bytes -= adv_bytes; ``` And if winepulse is just a little bit faster than the audio server (does not matter PW or PA), it inevitably leads to pointer overlaps and therefore crackling. This patch proposes a throttling mechanism that is somewhat similar to winealsa - don't ever tell the application we have more space than we actually do. The problem could probably be resolved by making the fake clock perfectly mimic the audio server, but this is orders of magnitude more difficult. Winealsa achieves similar idea this way: `data_frames_played = min(stream->data_in_alsa_frames, avail); stream->held_frames -= data_frames_played;` The issue I am trying to fix is very real - it can cause crackling in any game you try. You don't have to hear the crackling to see that it's mathematically inevitable by logging the difference between held_bytes and pa_held_bytes. If it becomes smaller and goes negative - crackling is inevitable, because pointers will overlap. The issue is not tied to PW or PA specifically, I observed the behavior with both. In regards to how it interacts with MR https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 - no issues in GoWR in my testing, unless you try enabling PROTON_LOG for pulse (which is very spammy in this game), and spam yes on all threads - which would also cause stream resets with unchanged winepulse, just later. Additionally, this patch has already been implemented in Proton GE and Proton CachyOS for about two months now - no issues and it has helped some people. There are not a lot of open issues regarding audio because unfortunately crackling is very underreported - you can look at GoWR protondb page before the 8628 MR - it definitely crackled, but many reports were not stating so. There are a lot of reports of crackling on virtually any game on protondb. You can also see people solve crackling issues for Arc Raiders (which I personally had myself before patching winepulse) by using winealsa: https://github.com/ValveSoftware/Proton/issues/9164#issuecomment-3529760335. One thing to look out for though - in CI spatialaudio tests will fail, but they fail literally the same way they do with winealsa - this is because there is nowhere for audio to go in a virtual environment, pa_held_bytes balloons while held_bytes drops, they overlap and held_bytes stops moving, and the tests start failing. No issues locally. I have previously tried tackling crackling in this pr: https://gitlab.winehq.org/wine/wine/-/merge_requests/9840 (although it was for underflows instead). My approach was admittedly incorrect, however it did help me discover this issue. Good audio is fundamental in my opinion, I would really love to see crackling-free audio for everyone regardless of proton version. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792
From: Dzmitry Keremsha <vyro@lumencoil.com> --- dlls/winepulse.drv/pulse.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index abc5e60821f..c512d5e5717 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -1565,6 +1565,7 @@ static NTSTATUS pulse_timer_loop(void *args) LARGE_INTEGER delay; pa_usec_t last_time; UINT32 adv_bytes; + SIZE_T safe_bytes; int success; pulse_lock(); @@ -1626,12 +1627,22 @@ static NTSTATUS pulse_timer_loop(void *args) if (stream->dataflow == eRender) { pulse_write(stream); - - /* regardless of what PA does, advance one period */ - adv_bytes = min(stream->period_bytes, stream->held_bytes); - stream->lcl_offs_bytes += adv_bytes; - stream->lcl_offs_bytes %= stream->real_bufsize_bytes; - stream->held_bytes -= adv_bytes; + safe_bytes = stream->period_bytes; + + if ((stream->held_bytes > stream->pa_held_bytes)) + { + SIZE_T limit = stream->held_bytes - stream->pa_held_bytes; + if (safe_bytes > limit) + safe_bytes = limit; + } + else { + safe_bytes = 0; + } + + adv_bytes = safe_bytes; + stream->lcl_offs_bytes += adv_bytes; + stream->lcl_offs_bytes %= stream->real_bufsize_bytes; + stream->held_bytes -= adv_bytes; } else if(stream->dataflow == eCapture) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10792
I doubt this is correct. Advancing read pointer affects app-visible timing, and that is an invariant: the audio timing should advance strictly real time based. It is not only audio related even, some game engines base game time on mmdevapi time. That's why '`/* regardless of what PA does, advance one period */'.` Whenever the actual crackling problem is I suppose it should be solved else wise, without compromising app's audio timing following pulse audio setup. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138462
On Thu Apr 30 21:33:35 2026 +0000, Paul Gofman wrote:
I doubt this is correct. Advancing read pointer affects app-visible timing, and that is an invariant: the audio timing should advance strictly real time based. It is not only audio related even, some game engines base game time on mmdevapi time. That's why '`/* regardless of what PA does, advance one period */'.` Whenever the actual crackling problem is I suppose it should be solved else wise, without compromising app's audio timing following pulse audio setup. Thanks for the feedback. Then this looks like a pretty serious problem, because the timer is incorrect. I still think it is sensible to not lie about the reality - but the timer must be fixed to avoid the issues altogether. There is no winning here otherwise - either some games are slower and don't crackle, or they aren't slow and crackle.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138463
There is no winning here otherwise - either some games are slower and don't crackle, or they aren't slow and crackle.
There are other options. First of all, yes, I guess the current timer management itself with relative delays is not accurate and it is solved with https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 which is however stuck for some reason. Then, the audio surely doesn't crackle for every PA setup and every game. The first thing here is to understand what is going wrong with the specific setup and game. Then, worst case, if there is indeed a systematic problem and it can't be solved by avoiding incompatible PA setups the solution is maybe introducing a separate PA update loop with its own buffer, so that PA audio pushes are decoupled from mmdevapi timeline. But before going for this complication I believe the actual exact problem must be understood. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138464
On Thu Apr 30 21:46:15 2026 +0000, Paul Gofman wrote:
There is no winning here otherwise - either some games are slower and don't crackle, or they aren't slow and crackle. There are other options. First of all, yes, I guess the current timer management itself with relative delays is not accurate and it is solved with https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 which is however stuck for some reason. Then, the audio surely doesn't crackle for every PA setup and every game. The first thing here is to understand what is going wrong with the specific setup and game. Then, worst case, if there is indeed a systematic problem and it can't be solved by avoiding incompatible PA setups the solution is maybe introducing a separate PA update loop with its own buffer, so that PA audio pushes are decoupled from mmdevapi timeline. But before going for this complication I believe the actual exact problem must be understood. I actually compared your PR to old winepulse and indeed it seemingly was starting to crackle a lot faster with the old one. The problem is that pointers still overlap maybe half an hour in even with your patch. The problem is widespread (from my experience on forums and such), but unfortunately I only have one PC at my disposal. If i can provide some additional logs for this I'd be happy to, but I need to know what exactly besides the ones proving pointers overlap.
FWIW I tried two distros, two soundcards and different kernels. CachyOS kernel helps with underflows but it's a different issue altogether. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138465
On Thu Apr 30 21:59:40 2026 +0000, Dzmitry Keremsha wrote:
I actually compared your PR to old winepulse and indeed it seemingly was starting to crackle a lot faster with the old one. The problem is that pointers still overlap maybe half an hour in even with your patch. The problem is widespread (from my experience on forums and such), but unfortunately I only have one PC at my disposal. If i can provide some additional logs for this I'd be happy to, but I need to know what exactly besides the ones proving pointers overlap. FWIW I tried two distros, two soundcards and different kernels. CachyOS kernel helps with underflows but it's a different issue altogether. Today with some help I tested:
Honkai Star Rail, Hades, Balatro Tested on three PCs, PC 1 and 3 for honkai, PC 1 and 2 for Balatro and PC 1 for Hades. All show the same behavior - slow timer drift. I attached a log that looks like this in the pulse.c code: ``` pulse_write(stream); TRACE("Buffer comparison: pa_held_bytes: %lu, held_bytes: %lu, diff: %ld\n", (unsigned long)stream->pa_held_bytes, (unsigned long)stream->held_bytes, (long)((long)stream->held_bytes - (long)stream->pa_held_bytes)); /* regardless of what PA does, advance one period */ adv_bytes = min(stream->period_bytes, stream->held_bytes); stream->lcl_offs_bytes += adv_bytes; stream->lcl_offs_bytes %= stream->real_bufsize_bytes; stream->held_bytes -= adv_bytes; ``` Tested Proton 11 and Proton GE, Proton GE had the last winepulse commit from Proton 10 without any additional patches, and Proton 11 is unchanged aside from the trace. Logged like this: WINEDEBUG=+pid,+loaddll,+timestamp,+debugstr,+threadname,+dsound,+dsound3d,+xaudio2,+mmdevapi,+pulse and PULSE_LATENCY_MSEC=60 to avoid crackling while getting the log spam. Without the latency variable, for example in Hades, I would get a very quick timer drift compared with frequent underflows (underflows do not happen without the logs so it's caused by them) [balatro-proton11-log.tar.gz](/uploads/8702ffc0fb47211004b28710591fb09d/balatro-proton11-log.tar.gz) To make sure this isn't about the differences in upstream Proton and GE, I tested Balatro with both and had the same outcome. I will only attach the Proton 11 Balatro log because of the size limits, however I can send the rest if needed. Regarding pipewire setup - everything is default and untouched except added RT capabilities on every machine. The pattern looks like this - winepulse timer is mostly in lockstep with the real time (by which I assume PipeWire). Sometimes, however, the audio server would consume less than it received, indicating that winepulse was a bit too fast. Since we don't have a throttling mechanism, we are now permanently ahead of reality. Wait long enough and the pointers would overlap and therefore it will crackle. An interesting discovery is that with the default pipewire-pulse quant of 256 (as of the new default in PipeWire 1.6) and PULSE_LATENCY_MSEC=60 the mmdevapi period is 15ms. In Honkai this is actually a huge problem - several crackles per second about one-two minutes in, specifically not underflow related. With the quant manually set to 480 - and therefore mmdevapi period becoming 10ms - there is a very slow drift which results in crackling in about 30 minutes for me. For PC 3 (pw-pa quant 480 and PULSE_LATENCY_MSEC=60) the drift actually only started occuring in 20-30 minutes of gameplay and was perfect before that. Yet another thing I noticed - the crackling is genuinely harder to spot when playing with speakers, for instance with bad HSR crackling and my laptop speakers I had to stand next to the speakers to hear them (probably something with the frequency they produce), while they are very loud and clear when listening through headphones. So as we can see, with the current winepulse timer implementation and without some sort of a throttling mechanism crackling is inevitable, be it in 10 minutes or 10 hours, at least on the hardware I tested. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138566
An interesting discovery is that with the default pipewire-pulse quant of 256 (as of the new default in PipeWire 1.6) and PULSE_LATENCY_MSEC=60 the mmdevapi period is 15ms.
Pulse latency should be \<10ms for Wine to work correctly, anything \>10ms is de-facto broken now. It is not about crackling in the first place, currently mmdevapi effectively sets minimum period to max(10ms, pulse latency). It can't force lower (unless we are going to implement a separate data feed thread for pulse decoupled from application data consuming thread). On Windows min period is always \~10ms and anything bigger outright breaks some games (make them crash) or may induce audio problems in other. The way is to avoid ever setting pulse latency \>10ms (\~3ms is probably a goo dstarting poin), I think there is no reason to have higher pulse latencies. I know people sometimes try to work around some problems this way but for Wine that is just broken.
The pattern looks like this - winepulse timer is mostly in lockstep with the real time (by which I assume PipeWire). Sometimes, however, the audio server would consume less than it received, indicating that winepulse was a bit too fast. Since we don't have a throttling mechanism, we are now permanently ahead of reality. Wait long enough and the pointers would overlap and therefore it will crackle.
If there is a slow time drift I'd expect it to lead to starvation or dropping buffer data once in that mentioned 30 minutes and then things to work just fine for another 30 minutes. The current way is supposed to effectively sync-time, possibly with data drop once in a while but that would be hard to notice. If that doesn't happen with the suitable pulse parameters (latency \< 10ms) maybe there is some other issue with implicit time catch up logic and we should be fixing that one. It is also possible that the issue is related to specific games which misbehave on Wine due to some incompatibility not even related to pulse timing. Then, does those affected games use mmdevapi directly even, or the issue might in fact be in, say, xaudio or dinput? \\>So as we can see, with the current winepulse timer implementation and without some sort of a throttling mechanism crackling is inevitable, be it in 10 minutes or 10 hours, at least on the hardware I tested. Well, I don't quite see that from the existing info. Maybe it worth opening Wine bug ticket with detailed repro instructions, which would describe the issue with specific game and reproduced with upstream Wine, along with pulse customization details (and provided latency is \<10ms). If it is reproducible only with official Proton, a proper place for that is Proton github issue tracker (reproducing and attaching PROTON_LOG=+pulse,+mmdevapi,+xaudio2,+dsound , strictly using official Proton and not downstream modifications). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138620
On Sat May 2 00:31:07 2026 +0000, Paul Gofman wrote:
An interesting discovery is that with the default pipewire-pulse quant of 256 (as of the new default in PipeWire 1.6) and PULSE_LATENCY_MSEC=60 the mmdevapi period is 15ms. Pulse latency should be \<10ms for Wine to work correctly, anything \>10ms is de-facto broken now. It is not about crackling in the first place, currently mmdevapi effectively sets minimum period to max(10ms, pulse latency). It can't force lower (unless we are going to implement a separate data feed thread for pulse decoupled from application data consuming thread). On Windows min period is always \~10ms and anything bigger outright breaks some games (make them crash) or may induce audio problems in other. The way is to avoid ever setting pulse latency \>10ms (\~3ms is probably a goo dstarting poin), I think there is no reason to have higher pulse latencies. I know people sometimes try to work around some problems this way but for Wine that is just broken. The pattern looks like this - winepulse timer is mostly in lockstep with the real time (by which I assume PipeWire). Sometimes, however, the audio server would consume less than it received, indicating that winepulse was a bit too fast. Since we don't have a throttling mechanism, we are now permanently ahead of reality. Wait long enough and the pointers would overlap and therefore it will crackle. If there is a slow time drift I'd expect it to lead to starvation or dropping buffer data once in that mentioned 30 minutes and then things to work just fine for another 30 minutes. The current way is supposed to effectively sync-time, possibly with data drop once in a while but that would be hard to notice. If that doesn't happen with the suitable pulse parameters (latency \< 10ms) maybe there is some other issue with implicit time catch up logic and we should be fixing that one. It is also possible that the issue is related to specific games which misbehave on Wine due to some incompatibility not even related to pulse timing. Then, does those affected games use mmdevapi directly even, or the issue might in fact be in, say, xaudio or dinput? \\>So as we can see, with the current winepulse timer implementation and without some sort of a throttling mechanism crackling is inevitable, be it in 10 minutes or 10 hours, at least on the hardware I tested. Well, I don't quite see that from the existing info. Maybe it worth opening Wine bug ticket with detailed repro instructions, which would describe the issue with specific game and reproduced with upstream Wine, along with pulse customization details (and provided latency is \<10ms). If it is reproducible only with official Proton, a proper place for that is Proton github issue tracker (reproducing and attaching PROTON_LOG=+pulse,+mmdevapi,+xaudio2,+dsound , strictly using official Proton and not downstream modifications). To explain things better and as to why my patch is necessary with the timer drift:
1. Timer drift means that wine mmdevapi is slightly faster than pipewire (which is the real time), so the rate of refill is higher than the rate of consumption. 2. pa_held_bytes balloons because on average we, for instance, refill 480 frames and consume 479. Held bytes, as you can see from the log, is consistent, it does not deviate from the margins of it's refill and drain long-term 3. pa_held_bytes grows infinitely -\> held bytes is the same -\> game thinks we have space for 500 frames, we have space for 30. Result - the game would refill it's usual 480 (an example) frames and we have an overlap of 450 frames - sounds like a crackle or static buzz. 4. pa_held_bytes is permanently high now, any overfill = crackle. You can see in that balatro log we have pa_held_bytes that is hovering around 0 and then after some point it stops (just look at the end of the log), as it got higher permanently. Please keep in mind it's happens even proper mmdevapi period so it's not about that. With my patch we never lie to the game - if we only have space for 30 frames, we are telling the game the truth, and hit backpressure which is the correct mechanism for that situation. Now if the wine mmdevapi timer is perfect, we would literally never hit the throttle, gain 480, spend 480, perfect equilibrium. Moreover, this mechanism is in alsa already. Ultimately the incorrect timer is what should be fixed, but the throttle is not harmful in any way. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138634
Timer drift means that wine mmdevapi is slightly faster than pipewire (which is the real time), so the rate of refill is higher than the rate of consumption.
It would be interesting why. Note that at least current time logic in Wine bases adjustments on PA stream time so it is supposed to match stream time of average. So if it consistently getting less writes and that builds up over some 30 minutes there might be some bug in that part (or some rounding error, so it would constistently err on one side somewhere estimating time or getting number of samples??). Note that this alone, while interesting, might not give the whole story anyway. Explanation sounds like this is the generic universal Wine problem, but this doesn't look to be the case. The audio doesn't crackle on the majority of setups for every game. There is no undertstadning currently what is special here, special inventive PA setup or maybe not but some issue with the specific game or engine (and the issue can in theory be in the specific audio API it is using even, e. g., xaudio).
pa_held_bytes is permanently high now, any overfill = crackle. Since pa_held_bytes is at it's limit, it now happens quite frequently.
Once again, the logic of app-visible update is an invariant, we are not free to change it to follow PA specifics without breaking compatibility with apps. But this is not the only option. I was mentioning an (rather complicated) alternative approach before. Another probably better way would be to just drop 'pa_held' buffer part once such a situation is detected. So at the moment of dropping it might have (probably hardly noticable?) hitch but then be fine for another half an hour. Either way, the way is it to adapt / interface PA side, not compromise app-visible side. For the latter approach with dropping PA buffer I personally would not be strictly opposed to that (unlike the current approach), even if there is no 100% understanding of the actual issue (which would probably be very useful to fix the actual problem). Dealing with the consequences which already happened for some reason (which reason can be incompatible PA setup out of our control) is probably better this way than letting pa_held_bytes stay permanently high. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138647
On Sat May 2 15:16:09 2026 +0000, Paul Gofman wrote:
Timer drift means that wine mmdevapi is slightly faster than pipewire (which is the real time), so the rate of refill is higher than the rate of consumption. It would be interesting why. Note that at least current time logic in Wine bases adjustments on PA stream time so it is supposed to match stream time of average. So if it consistently getting less writes and that builds up over some 30 minutes there might be some bug in that part (or some rounding error, so it would constistently err on one side somewhere estimating time or getting number of samples??). Note that this alone, while interesting, might not give the whole story anyway. Explanation sounds like this is the generic universal Wine problem, but this doesn't look to be the case. The audio doesn't crackle on the majority of setups for every game. There is no undertstadning currently what is special here, special inventive PA setup or maybe not but some issue with the specific game or engine (and the issue can in theory be in the specific audio API it is using even, e. g., xaudio). pa_held_bytes is permanently high now, any overfill = crackle. Since pa_held_bytes is at it's limit, it now happens quite frequently. Once again, the logic of app-visible update is an invariant, we are not free to change it to follow PA specifics without breaking compatibility with apps. But this is not the only option. I was mentioning an (rather complicated) alternative approach before. Another probably better way would be to just drop 'pa_held' buffer part once such a situation is detected. So at the moment of dropping it might have (probably hardly noticable?) hitch but then be fine for another half an hour. Either way, the way is it to adapt / interface PA side, not compromise app-visible side. For the latter approach with dropping PA buffer I personally would not be strictly opposed to that (unlike the current approach), even if there is no 100% understanding of the actual issue (which would probably be very useful to fix the actual problem). Dealing with the consequences which already happened for some reason (which reason can be incompatible PA setup out of our control) is probably better this way than letting pa_held_bytes stay permanently high. Honestly I am not sure myself what is happening either and why the reports aren't universal. So far there has not been a single case where I could play any game without the timer drifting (and surely enough crackling with enough time), and the problem has persisted across the hardware/kernels/etc I've tested.
I'd like to ask you what bad things can hypothetically can happen if held_bytes gets throttled - and I'd like to test some games/programs you know of where something breaking could happen. As it stands now - I am literally unable to play without crackling ever without either this patch or winealsa which basically does the same thing, so I am curious how the edge cases behave. Most games are fine though, they are okay with the fact that the audio thread can be stopped. Maybe it can cause something bad, but so far the logic I describe has to exist at least as a variable in downstream protons so people with such issues (me included) can play games without constant crackling half an hour in. If I understand correctly then the games that tie their game logic to mmdevapi would be a tiny bit faster when mmdevapi is fast, and if they hit the throttle they would slow down to compensate for their overspeed. Maybe I misunderstand something though. There have been no cases so far of games outright crashing or audio glitches from the public reports. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138651
Another probably better way would be to just drop 'pa_held' buffer part once such a situation is detected.
pa_held is physical audio though, when it's full it's very roughly \~25ms usually. That would be a loud and annoying crackle happening every half an hour, or worst case much often. There has to be a way to somehow solve this without compromising anything. Regarding the PA setups - I honestly don't even know what there is to break in the first place, my tests were 1. just regular PipeWire 1.6 with absolutely nothing added 2. quant 480 for pipewire-pulse Native games and apps do not ever have any issues either. Moreover I did try pulseaudio instead of pipewire, and without touching any config files and the behavior was the same. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138655
pa_held is physical audio though, when it's full it's very roughly \~25ms usually. That would be a loud and annoying crackle happening every half an hour, or worst case much often. There has to be a way to somehow solve this without compromising anything.
Why loud? That is supposed to be just a ps_held length skip in audio, without loud garbage added. But anyway, I would agree that it is not ideal, it would be better to understand why time difference builds up and fix that. Currently it is supposed to catch up with app's visible mmdevapi audio quantum interval slightly dynamically adjusted, if that doesn't happen it is interesting why exactly and probably that is the part which should ideally be fixed one or another way.
quant 480 for pipewire-pulse
Which exactly units and parameter is that? What is the minimum period our mmdevapi actually ends up with? If that is more than 10 ms (stupulated by pulse latency) this can't work right now. We did have examples of issues (at least on Proton tracker) with such setup just breaking games (due to too high device period which never happens on Windows). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138672
Why loud?
Yeah maybe not the most appropriate description, in my head underflow = loud, overlap = quiet, deleting data sounds like an underflow, hence loud. My exact pulse.properties config in \~/.config/pipewire: ``` #server.dbus-name = "org.pulseaudio.Server" #pulse.allow-module-loading = true pulse.min.req = 480/48000 pulse.default.req = 480/48000 pulse.min.frag = 480/48000 #pulse.default.frag = 96000/48000 # 2 seconds #pulse.default.tlength = 96000/48000 # 2 seconds pulse.min.quantum = 480/48000 #pulse.idle.timeout = 0 # don't pause after underruns #pulse.default.format = F32 #pulse.default.position = [ FL FR ] #pulse.fix.position = [ FL FR ] ``` Allows for 10ms mmdev period with PULSE_LATENCY_MSEC=60 (so I can properly log without underflows) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138673
On Sun May 3 22:47:19 2026 +0000, Dzmitry Keremsha wrote:
Why loud? Yeah maybe not the most appropriate description, in my head underflow = loud, overlap = quiet, deleting data sounds like an underflow, hence loud. (EDIT: actually it's not like an underflow, but it would most likely be very noticeable and not a proper solution either way) My exact pulse.properties config in \~/.config/pipewire:
#server.dbus-name = "org.pulseaudio.Server" #pulse.allow-module-loading = true pulse.min.req = 480/48000 pulse.default.req = 480/48000 pulse.min.frag = 480/48000 #pulse.default.frag = 96000/48000 # 2 seconds #pulse.default.tlength = 96000/48000 # 2 seconds pulse.min.quantum = 480/48000 #pulse.idle.timeout = 0 # don't pause after underruns #pulse.default.format = F32 #pulse.default.position = [ FL FR ] #pulse.fix.position = [ FL FR ]Allows for 10ms mmdev period with PULSE_LATENCY_MSEC=60 (so I can properly log without underflows) For clarity 15ms was quant 256+PULSE_LATENCY_MSEC=60, hence that was in the log i sent. Quant 256 without the variable is 10ms so that'd be good as well, but then underflows with logs. I have done extensive testing in the past few days and here are my observations:
1. No drift whatsoever with a virtual sink after an hour of logging. 2. The timer math looks correct and there are no truncation errors, mmdev usec is 10000. It might be possible that pulse is consuming based on the soundcard clock which could be at 47999 sample rate instead of 48000, in which case overfill is unavoidable even with a perfect timer. One way to solve this would be a dynamic resampler, which did seem to work in my testing, does not affect held_bytes and is absolutely unnoticeable. What do you think about this idea? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138984
On Wed May 6 13:02:13 2026 +0000, Dzmitry Keremsha wrote:
I have done extensive testing in the past few days and here are my observations: 1. No drift whatsoever with a virtual sink after an hour of logging. 2. The timer math looks correct and there are no truncation errors, mmdev usec is 10000. It might be possible that pulse is consuming based on the soundcard clock which could be at 47999 sample rate instead of 48000, in which case overfill is unavoidable even with a perfect timer. One way to solve this would be a dynamic resampler, which did seem to work in my testing, does not affect held_bytes and is absolutely unnoticeable. What do you think about this idea? Can't we somehow tie our timer to the soundcard clock? I mean, instead of using a fixed offset to calculate the wait time, can we base it on the actual rate of consumption by PA?
Something similar is done in `dlls/dmsynth/synthsink.c`, which uses DirectSound position notifications to to get a precise playback position and then extrapolates it to calculate the wait time. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138986
Can't we somehow tie our timer to the soundcard clock? I mean, instead of using a fixed offset to calculate the wait time, can we base it on the actual rate of consumption by PA?
That is what is supposed to be happening at least with current upstream, without any extra patches on top. The time adjustments is based on PA stream timing which is supposed to match the actual PA consumption / soundcard timing. Are you actually checking with upstream Wine and not only with downstream solutions? If It might be that my patch I was referencing above is different in this case and should be fixed. Otherwise, it is interesting what is actually going on there, why the time error stacks up on the long run: is it still something wrong in the current code or maybe pulse stream timing is wrong and doesn't reflect the time difference (if the different timeline is the root cause indeed)? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138990
On Wed May 6 15:04:43 2026 +0000, Paul Gofman wrote:
Can't we somehow tie our timer to the soundcard clock? I mean, instead of using a fixed offset to calculate the wait time, can we base it on the actual rate of consumption by PA? That is what is supposed to be happening at least with current upstream, without any extra patches on top. The time adjustments is based on PA stream timing which is supposed to match the actual PA consumption / soundcard timing. Are you actually checking with upstream Wine and not only with downstream solutions? If It might be that my patch I was referencing above is different in this case and should be fixed. Otherwise, it is interesting what is actually going on there, why the time error stacks up on the long run: is it still something wrong in the current code or maybe pulse stream timing is wrong and doesn't reflect the time difference (if the different timeline is the root cause indeed)? It is also possible in theory that winepulse timer adjustment is fine but something up the stack (higher level Wine sound libraries like xaudio, the game itself) is not working very well under such conditions, maybe, just e. g., (one of many possibilities) mmdevapi period rounding should be consistent with the actual device timing and timeline adjustments won't always work very well without that.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138991
On Wed May 6 15:15:21 2026 +0000, Paul Gofman wrote:
It is also possible in theory that winepulse timer adjustment is fine but something up the stack (higher level Wine sound libraries like xaudio, the game itself) is not working very well under such conditions, maybe, just e. g., (one of many possibilities) mmdevapi period rounding should be consistent with the actual device timing and timeline adjustments won't always work very well without that. Previously I was noticing on WIndows that while minimum shared mmdevapi period sticks to \~10ms the exact values may vary, what if that actually has something to do with the issue (that's more of a wild guess rather than a conclusion, a lot of factors is in play here).
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138992
That is what is supposed to be happening at least with current upstream, without any extra patches on top. The time adjustments is based on PA stream timing which is supposed to match the actual PA consumption / soundcard timing. Are you actually checking with upstream Wine and not only with downstream solutions?
Yeah, sorry, I misread the code. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_138998
On Wed May 6 16:25:39 2026 +0000, Anton Baskanov wrote:
That is what is supposed to be happening at least with current upstream, without any extra patches on top. The time adjustments is based on PA stream timing which is supposed to match the actual PA consumption / soundcard timing. Are you actually checking with upstream Wine and not only with downstream solutions? Yeah, sorry, I misread the code. just Wine in Stardew Valley without patches: pa_held_bytes doesn't grow at least in 15m of testing. Very surprised because Honkai did with pulse before MR 8628. Wine with 8628 definitely grows. Sorry, should have checked earlier. Will do more testing, maybe something would go wrong with more time and upstream pulse.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139000
On Wed May 6 16:52:52 2026 +0000, Dzmitry Keremsha wrote:
just Wine in Stardew Valley without patches: pa_held_bytes doesn't grow at least in 15m of testing. Very surprised because Honkai did with pulse before MR 8628. Wine with 8628 definitely grows. Sorry, should have checked earlier. Will do more testing, maybe something would go wrong with more time and upstream pulse. That's quite possible, https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 use pulse global time and not stream / device time. While that MR may improve shorter term timer accuracy it could introduce such a small drift. See the last paragraph in the description. Using just a separate timer per stream defeats the purpose there, the main motivation of that MR was to remove incompatibility coming from not synced streams updates breaking game(s). But perhaps per-device timers (adjusted based on a stream time) should work, while also I think resetting pa_held bytes if we run out of buffer is also a valid fallback. I might look at that further at some moment.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139004
On Wed May 6 17:15:00 2026 +0000, Paul Gofman wrote:
That's quite possible, https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 use pulse global time and not stream / device time. While that MR may improve shorter term timer accuracy it could introduce such a small drift. See the last paragraph in the description. Using just a separate timer per stream defeats the purpose there, the main motivation of that MR was to remove incompatibility coming from not synced streams updates breaking game(s). But perhaps per-device timers (adjusted based on a stream time) should work, while also I think resetting pa_held bytes if we run out of buffer is also a valid fallback. I might look at that further at some moment. I assume skipping audio would be somewhat similar to skipping a beat in a song - it somehow sounds unsettling. Especially if the user sets their latency higher to avoid underflows - I am quite certain at 45ms (which does not actually contradict 10ms mmdev timer, you can crank latency way up with quant 480 in pw-pulse and PULSE_LATENCY_MSEC and keep 10ms mmdev) it would be very noticeable, so hopefully there is another way to solve this.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139005
it would be very noticeable
Don't think so, we are talking about a few ms of audio once per half an hour. Note you don't have to skip full 45ms buffer. While I think finding a better way to sync timing under normal conditions is interesting. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139006
On Wed May 6 17:46:16 2026 +0000, Paul Gofman wrote:
it would be very noticeable Don't think so, we are talking about a few ms of audio once per half an hour. Note you don't have to skip full 45ms buffer. While I think finding a better way to sync timing under normal conditions is interesting. I honestly think that consciously dropping some pa_held data in case of buffer overrun would be a good thing to do either way. If for whatever reason we end up with data overrun it is better to handle it and drop the history (effectively catch up timeline) than allowing the thing to work for the rest of stream existence in a broken mode playing garbage.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139007
If for whatever reason we end up with data overrun it is better to handle it and drop the history (effectively catch up timeline) than allowing the thing to work for the rest of stream existence in a broken mode playing garbage.
Absolutely, no doubt about that. Did some more testing - everything is good. Also tested Balatro and Honkai with pulse before MR 8628, everything is okay, so there must have been some mistake on my part before. Thanks for helping with investigation, looking forward to crackle-free audio! -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139010
This merge request was closed by Dzmitry Keremsha. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792
@Vyrolian I've updated https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 , do you mind checking if the new version doesn't introduce the issue for you? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139155
On Fri May 8 01:17:56 2026 +0000, Paul Gofman wrote:
@Vyrolian I've updated https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 , do you mind checking if the new version doesn't introduce the issue for you? So far the stream outright dies in Stardew Valley (just Wine) with an underflow. Why it underflows to begin with I am not sure either - I had to set wine to a ridiculous latency to begin with because without it there were underflows with upstream and older versions of pulse for some reason. However this should be mmdev of 10ms still.
Also I am not sure this is the case but could it be that the master version of wine is necessary? This is 11-8. [stardewlog.tar.xz](/uploads/a08a76eecc453a87c24b3bc1d4d8a132/stardewlog.tar.xz) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139159
On Fri May 8 01:17:56 2026 +0000, Dzmitry Keremsha wrote:
So far the stream outright dies in Stardew Valley (just Wine) with an underflow. Why it underflows to begin with I am not sure either - I had to set wine to a ridiculous latency to begin with because without it there were underflows with upstream and older versions of pulse for some reason. However this should be mmdev of 10ms still. Also I am not sure this is the case but could it be that the master version of wine is necessary? This is 11-8. [stardewlog.tar.xz](/uploads/a08a76eecc453a87c24b3bc1d4d8a132/stardewlog.tar.xz) Forgot to include all the other stuff in the logs aside from pulse, if that's helpful:
[stardew-log.tar.xz](/uploads/9349be23b58d469d5ee8831a3882f885/stardew-log.tar.xz) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139160
I had to set wine to a ridiculous latency to begin with
What do you mean by this, exactly? Set where and how? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139161
On Fri May 8 01:25:44 2026 +0000, Paul Gofman wrote:
I had to set wine to a ridiculous latency to begin with What do you mean by this, exactly? Set where and how? Quant 480 in pw-pulse and PULSE_LATENCY_MSEC=120 during launch. I did test with these parameters before and it worked properly, no pa_held_bytes growth or any weirdness
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139162
On Fri May 8 01:27:16 2026 +0000, Dzmitry Keremsha wrote:
Quant 480 in pw-pulse and PULSE_LATENCY_MSEC=120 during launch. I did test with these parameters before and it worked properly, no pa_held_bytes growth or any weirdness These underflow issues that warrant such latency are somehow related to launching with just wine I am sure, I never set latency that high normally, in most games there is no need to change anything even, especially in the lighter ones.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139164
44066.349:0020:0160:trace:pulse:pa_streams_timer_cb Buffer comparison: pa_held_bytes: 0, held_bytes: 19200, diff: 19200
I don't have this trace in my code, there is something else on top. The immediate reason is apparently that something went very wrong with the scheduling next time for pa_streams_timer_cb() but I can't guess what exactly from existing info. What exactly are you building, can we start with just upstream and my patch if possible? If that reproduces the issue I could probably add a bit more logging (I'd started from checking that pa_stream_get_time() succeeds in pa_streams_timer_cb and then logging stream_time and all the conditions there (just_underran, just_started), and what next_timer it actually ends up with right before pa_context_rttime_restart()). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139169
On Fri May 8 01:37:25 2026 +0000, Paul Gofman wrote:
44066.349:0020:0160:trace:pulse:pa_streams_timer_cb Buffer comparison: pa_held_bytes: 0, held_bytes: 19200, diff: 19200 I don't have this trace in my code, there is something else on top. The immediate reason is apparently that something went very wrong with the scheduling next time for pa_streams_timer_cb() but I can't guess what exactly from existing info. What exactly are you building, can we start with just upstream and my patch if possible? If that reproduces the issue I could probably add a bit more logging (I'd started from checking that pa_stream_get_time() succeeds in pa_streams_timer_cb and then logging stream_time and all the conditions there (just_underran, just_started), and what next_timer it actually ends up with right before pa_context_rttime_restart()). But looking at the code, whatever goes with the stream time I am not sure how that can happen that pa_streams_timer_cb is just never called again throughout some seconds (even if time adjustment is completely wrong it is limited in value). That's why it is important to first remove any other changes.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139170
On Fri May 8 01:40:25 2026 +0000, Paul Gofman wrote:
But looking at the code, whatever goes with the stream time I am not sure how that can happen that pa_streams_timer_cb is just never called again throughout some seconds (even if time adjustment is completely wrong it is limited in value). That's why it is important to first remove any other changes. Building upstream right now, will take a bit, will report back asap. No changes aside from the log though - i literally copy pasted your code into mine. The log is to clearly see what's going on with pa_held_bytes, absolutely no modifications otherwise.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139171
On Fri May 8 01:43:19 2026 +0000, Dzmitry Keremsha wrote:
Building upstream right now, will take a bit, will report back asap. No changes aside from the log though - i literally copy pasted your code into mine. The log is to clearly see what's going on with pa_held_bytes, absolutely no modifications otherwise. Wait, it looks I reproduced that in my tests... will figure out.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139172
On Fri May 8 01:47:21 2026 +0000, Paul Gofman wrote:
Wait, it looks I reproduced that in my tests... will figure out. If it's of any help still - the things are definitely the same on upstream, and it's underflowing even with PULSE_LATENCY_MSEC=240 (still 10ms, does not happen with the upstream pulse even at 120).
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139173
On Fri May 8 02:40:22 2026 +0000, Dzmitry Keremsha wrote:
If it's of any help still - the things are definitely the same on upstream, and it's underflowing even with PULSE_LATENCY_MSEC=240 (still 10ms, does not happen with the upstream pulse even at 120). EDIT: for clarity I did use upstream previously, just wine 11-8 arch repos instead of master from the gitlab The issue itself is clear, it is just that looking more at various aspects looks like it is not ideal, will try to improve that tomorrow.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139174
On Fri May 8 02:40:54 2026 +0000, Paul Gofman wrote:
The issue itself is clear, it is just that looking more at various aspects looks like it is not ideal, will try to improve that tomorrow. @Vyrolian I've updated https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 , hope it should be better now. For one audio stream (as it seems to be the case with from the above log for that game) I'd expect it not to have de-facto differences with current upstream at all.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139501
On Mon May 11 22:28:20 2026 +0000, Paul Gofman wrote:
@Vyrolian I've updated https://gitlab.winehq.org/wine/wine/-/merge_requests/8628 , hope it should be better now. For one audio stream (as it seems to be the case with from the above log for that game) I'd expect it not to have de-facto differences with current upstream at all. [stardew-log.tar.xz](/uploads/e1cad03dd700f0b28546d6acc341e8e8/stardew-log.tar.xz)
On a very high latency - everything seems to be good. But with PULSE_LATENCY_MSEC=120 I had an underflow and then 59 more. It crackled a lot and played on a higher speed for a short while afterwards. I don't know what caused the underflow, but there was a rather steep adjust just before that. Either way if it was a natural underflow, the recovery from it does not seem right -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139504
On Mon May 11 23:43:50 2026 +0000, Dzmitry Keremsha wrote:
[stardew-log.tar.xz](/uploads/e1cad03dd700f0b28546d6acc341e8e8/stardew-log.tar.xz) On a very high latency - everything seems to be good. But with PULSE_LATENCY_MSEC=120 I had an underflow and then 59 more. It crackled a lot and played on a higher speed for a short while afterwards. I don't know what caused the underflow, but there was a rather steep adjust just before that. Either way if it was a natural underflow, the recovery from it does not seem right As usual - no adjustments aside from the log cause I need to see pa_held_bytes.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139505
On Mon May 11 23:45:26 2026 +0000, Dzmitry Keremsha wrote:
As usual - no adjustments aside from the log cause I need to see pa_held_bytes. Unable to reproduce again so far, can reproduce underflows on much lower latencies (120 is fine), but they seem normal.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139507
On Mon May 11 23:59:34 2026 +0000, Dzmitry Keremsha wrote:
Unable to reproduce again so far, can reproduce underflows on much lower latencies (120 is fine), but they seem normal. Thanks a lot for checking! So you don't see time drift / pa_held_bytes always climbing anymore? That should've been fixed.
I still don't understand why do you need that PULSE_LATENCY_MSEC. Maybe there is still something custom in PA setup? PULSE_LATENCY_MSEC affects (forces) buffer preroll, that can be responsible for longer settle time after underflow with my patch. While underflow itself may occur once in a while due to load of random reasons, like heavier machine load and game sometimes not keeping up due to various reasons). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139509
On Tue May 12 00:05:55 2026 +0000, Paul Gofman wrote:
Thanks a lot for checking! So you don't see time drift / pa_held_bytes always climbing anymore? That should've been fixed. I still don't understand why do you need that PULSE_LATENCY_MSEC. Maybe there is still something custom in PA setup? PULSE_LATENCY_MSEC affects (forces) buffer preroll, that can be responsible for longer settle time after underflow with my patch. While underflow itself may occur once in a while due to load of random reasons, like heavier machine load and game sometimes not keeping up due to various reasons). No, no drift at all. Thanks a lot for your work!
As to why PULSE_LATENCY_MSEC is needed in this specific scenario - I don't know either, no light games when using Proton requires it, and only a very rare heavy game does. This underflow bothers me a bit cause there was a huge jump in time, which has not happened since either - I've had absolutely normal underflows since. Will try to test Honkai, although this game would require Proton. It has two independent streams -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139510
On Tue May 12 00:17:56 2026 +0000, Dzmitry Keremsha wrote:
No, no drift at all. Thanks a lot for your work! As to why PULSE_LATENCY_MSEC is needed in this specific scenario - I don't know either, no light games when using Proton requires it, and only a very rare heavy game does. This underflow bothers me a bit cause there was a huge jump in time, which has not happened since either - I've had absolutely normal underflows since. Will try to test Honkai, although this game would require Proton. It has two independent streams To clarify - it just crackles with Wine and Stardew without PULSE_LATENCY_MSEC somehow, so I have to raise latency because to test pa_held_bytes I need a continuous stream.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139511
no light games when using Proton requires it, and only a very rare heavy game does.
It might be that in CPU heavy games under CPU starvation the game's + Wine audio threads do not keep up. What does 'ulimit -e' say? If it is not negative It might be that allowing thread priority increase for user (by editing /etc/security/limits.conf) can work better. if you run with WINEDEBUG=+server, do you see ("wine: RLIMIT_NICE is \<= 20, unable to use setpriority safely\\n") messages? If yes, Wine can't alter priorities due to limits. While unrelated here, I went ahead and pushed the updated patch version to the current Proton Experimental bleeding-edge branch (see https://github.com/ValveSoftware/Proton/wiki/Proton-Versions#proton-bleeding...), if you want to try with Proton you can use that version (experimental-bleeding-edge-11.0-359342-20260512-pd2f45d-w4531de-d6e9b50-v4ed1fe) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139512
On Tue May 12 00:48:03 2026 +0000, Paul Gofman wrote:
no light games when using Proton requires it, and only a very rare heavy game does. It might be that in CPU heavy games under CPU starvation the game's + Wine audio threads do not keep up. What does 'ulimit -e' say? If it is not negative It might be that allowing thread priority increase for user (by editing /etc/security/limits.conf) can work better. if you run with WINEDEBUG=+server, do you see ("wine: RLIMIT_NICE is \<= 20, unable to use setpriority safely\\n") messages? If yes, Wine can't alter priorities due to limits. While unrelated here, I went ahead and pushed the updated patch version to the current Proton Experimental bleeding-edge branch (see https://github.com/ValveSoftware/Proton/wiki/Proton-Versions#proton-bleeding...), if you want to try with Proton you can use that version (experimental-bleeding-edge-11.0-359342-20260512-pd2f45d-w4531de-d6e9b50-v4ed1fe) ulimit -e is 31, so niceness goes down to -11 as I understand? Should be fine then. No complaints in logs either. The soundcard itself is quite performant on linux in my experience with DAWs.
The CachyOS kernel does help with underflows too. For instance when I was on Fedora: * Default kernel in Honkai with 480 quant for pw-pulse: crackles * CachyOS kernel with the same parameters: doesn't crackle This is specifically about underflows, it did not prevent the drift. Winealsa does perform better but that's highly likely simply because tlength of winealsa is \~1.5x of winepulse tlength at the same quant. Could it be that tlength of 20ms (9600) is just not enough? I don't really know how much latency there is on Windows to compare. Maybe the timer drift played some role somehow, the only game on CachyOS that crackles with quant 480 for me so far is Neverness to Everness and it happens very rarely, so that'd be quite annoying to test. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139524
On Tue May 12 03:23:29 2026 +0000, Dzmitry Keremsha wrote:
ulimit -e is 31, so niceness goes down to -11 as I understand? Should be fine then. No complaints in logs either. The soundcard itself is quite performant on linux in my experience with DAWs. The CachyOS kernel does help with underflows too. For instance when I was on Fedora: * Default kernel in Honkai with 480 quant for pw-pulse: crackles * CachyOS kernel with the same parameters: doesn't crackle This is specifically about underflows, it did not prevent the drift. Winealsa does perform better but that's highly likely simply because tlength of winealsa is \~1.5x of winepulse tlength at the same quant. Could it be that tlength of 20ms (9600) is just not enough? I don't really know how much latency there is on Windows to compare. Maybe the timer drift played some role somehow, the only game on CachyOS that crackles with quant 480 for me so far is Neverness to Everness and it happens very rarely, so that'd be quite annoying to test. Regarding the catch-up after underflows - does not seem to be PULSE_LATENCY_MSEC related. Could reproduce by freezing and then resuming the game thread. Whether that's a concern - probably not, don't know. The thing I was worried about is that some games underflow during initial loading for instance and such a catch up would be quite unpleasant, but generally underflows don't warrant a lengthy catch up, I guess there should be a bad enough freeze for that.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139525
On Tue May 12 03:30:02 2026 +0000, Dzmitry Keremsha wrote:
Regarding the catch-up after underflows - does not seem to be PULSE_LATENCY_MSEC related. Could reproduce by freezing and then resuming the game thread. Whether that's a concern - probably not, don't know. The thing I was worried about is that some games underflow during initial loading for instance and such a catch up would be quite unpleasant, but generally underflows don't warrant a lengthy catch up, I guess there should be a bad enough freeze for that. Did some more testing. First of all - the patch works very well, no issues whatsoever.
Second - don't have any underflow issues even with quant 256 and the default Arch kernel in NtE or Honkai, so whatever used to cause them is gone. With Honkai probably forgot to turn off logging back then - it does cause underflows by itself since it's quite spammy. Now I remove all the spammy stuff when I look for the underflows, but there are none so far. I do see people asking for help regarding crackling on forums somewhat often, but that might be attributed to either old PipeWire defaults (it was below quant 256 in pw-pulse), or the old winepulse patch. After PipeWire 1.6 is more widely adopted and the pulse patch goes to stable it would become more clear if some issues persist, but so far everything looks good and doesn't require any tinkering. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139657
On Wed May 13 08:42:09 2026 +0000, Dzmitry Keremsha wrote:
Did some more testing. First of all - the patch works very well, no issues whatsoever. Second - don't have any underflow issues even with quant 256 and the default Arch kernel in NtE or Honkai, so whatever used to cause them is gone. With Honkai probably forgot to turn off logging back then - it does cause underflows by itself since it's quite spammy. Now I remove all the spammy stuff when I look for the underflows, but there are none so far. I do see people asking for help regarding crackling on forums somewhat often, but that might be attributed to either old PipeWire defaults (it was below quant 256 in pw-pulse), or the old winepulse patch. After PipeWire 1.6 is more widely adopted and the pulse patch goes to stable it would become more clear if some issues persist, but so far everything looks good and doesn't require any tinkering. Thanks a lot for checking. I guess I will still consider that MR a draft for now, this is a sensitive change which can use some broader feedback while in Proton Experimental. Besides, now with system threads introduced the audio stream threads in all the Wine audio drivers can be made such and that will remove a clumsy move exiting the stream thread in that MR which is still created.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10792#note_139711
participants (4)
-
Anton Baskanov (@baskanov) -
Dzmitry Keremsha -
Dzmitry Keremsha (@Vyrolian) -
Paul Gofman (@gofman)