http://bugs.winehq.org/show_bug.cgi?id=28723
--- Comment #32 from Jörg Höhle hoehle@users.sourceforge.net 2011-11-04 16:57:49 CDT --- *out = This->held_frames; Come to think of it, this is presumably what native GetCurrentPadding does in shared mode and what Wine should do. Native's shared mode GCP means the buffer is that much free, and the rest was sent to the mixer -- it does not mean that the rest was already "consumed" by the HW.
There are 2 issues, though: 1. Native mixes 10ms and sends them to the HW, whereas Wine has all of the ALSA buffer in front of it. As you experienced in comment #24, this adds latency as large as ALSA's buffer.
2. GetPosition in Wine is based on GetCurrentPadding. I wrote in http://www.winehq.org/pipermail/wine-devel/2011-August/091562.html that this is bogus, snd_pcm_delay must be used instead but I've not polished the patch since. With a fixed GetPosition, the modified GCP would pass my render.c tests.
Point 1. can be improved by calling snd_pcm_hw_params_set_buffer_time_max when duration is small (perhaps < 50ms?), revealing that the app wants tight timing. The final word has not been said yet on snd_pcm_set_period/buffer_min/max/near. I've not yet found an interesting formula and a good heuristic to distinguish 2 use cases: "size doesn't matter, just play" and "low-latency shooter reaction".
Something else to prevent underruns may be to pretend running at 10ms like native, but use a period of 5ms. This would hopefully account for the fact that ALSA's buffer filling need is not synchronized with mmdevapi's timer. Then again, try and find an heuristic not to always run at 5ms (e.g. PlaySound doesn't need that).