http://bugs.winehq.org/show_bug.cgi?id=30118
Bug #: 30118 Summary: Sound occasionally stalls past underrun, bypassing our lead-in writer Product: Wine Version: 1.4-rc5 Platform: x86 OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: winealsa.drv AssignedTo: wine-bugs@winehq.org ReportedBy: hoehle@users.sourceforge.net Classification: Unclassified
Attachment #39217 to bug #29294 contains a log where Civilization 5 audio stalls after an underrun.
99% of the time, an underrun happens while the mmdevapi render callback sleeps. snd_pcm_avail is then the first to detect it, recovers, writes the lead-in and audio is running again. This happened 266 times in the log: 62.063:alsa_write_data XRun state avail 12689, recovering
In rare cases, the underrun did not yet occur when snd_pcm_avail was called rather than a few µs later in snd_pcm_write. 62.190:alsa_write_data pad: 4245 62.190:alsa_write_best_effort writei failed, recovering: -32 (Broken pipe) ALSA lib pcm.c:7316:(snd_pcm_recover) underrun occurred
Following that, ALSA has a little data 62.201:alsa_write_data pad: 512 62.211:alsa:alsa_write_data pad: 5120 but somehow DSound stops feeding it.
Now bug #29294 involves Jack whose precise behaviour I don't know, but here's what would happen when using plain plug:dmix or hw:0: Our lead-in writer does not trigger because it sits before snd_pcm_write. The key issue is that ALSA has less than one period of data, so it doesn't start! That is known behaviour from both dmix and hw:x,y devices.
23.054:AudioClient_Initialize ALSA period: 5512 frames 23.055:AudioClient_Initialize ALSA buffer: 16537 frames 23.055:AudioClient_Initialize MMDevice period: 441 frames 23.055:AudioClient_Initialize MMDevice buffer: 5120 frames
As a result, position does not increase. The little data prevents writing the lead-in upon subsequent callback invocations. Unfortunately, DSound is presumably waiting for a particular position to be reached to continue feeding data.
Position would increase and bump to max = release_frames - held_frames if it would hit another underun -- if ALSA had managed to start.
So this is partly a bug in DSound which I've already blamed for using GetPosition instead of GetCurrentPadding when feeding data, witness comment #21, bug #29472, comment #17 or bug #29497, comment #1. However the subject of this bug report shall be winealsa's incomplete underrun recovery.
Also note another issue here: mmdevapi's buffer of 5120 frames is smaller than ALSA's period! Thanks to the lead-in, that nevertheless works at start. Perhaps DSound would not have stalled had that buffer been larger; it might have written more frames.
Months ago I conducted many tests with different buffer and period sizes in exclusive mode but have not finalized that work about the minimum and maximum buffer sizes and when to return E_INVALID_DEVICE_PERIOD or AUDCLNT_E_BUFFER_SIZE_ERROR etc. That's still a TODO on my list. That work has been very revealing about the relationship between mmdevapi and alsa buffer and period sizes. Presumably, mmdevapi must create a buffer at least as large as ALSA's period.