http://bugs.winehq.org/show_bug.cgi?id=29299
--- Comment #9 from Jörg Höhle hoehle@users.sourceforge.net 2012-01-24 05:40:27 CST --- Native's precondition to append silence would be: if (initially_held_frames (==held_frames+written) < mmdevapi_period)
However, ours is much more complicated because we may decrease padding by more than one mmdevapi period. Furthermore, we need to handle cases where a) alsa_period < mmdevapi_period b) alsa_period = mmdevapi_period c) alsa_period > mmdevapi_period
The scenario Release(30ms); Sleep(25ms); Release(more) is perfectly valid. We must not append silence even though our first callback write will move the 3 periods outside the sight of GCP, yielding held_frames == 0. I still need more time to think through the exact condition. There's also that if (held_frames == 0) early return that will get modified.
The lead-in patch is not quite correct. First, the comment is wrong. When we'll have a proper lead-out, its padding will have ALSA start. We don't need the lead-in for that. I invented the lead-in (or its equivalent, the start_threshold) solely to guarantee that ALSA has enough frames to play even in the XAudio2/Rage scenario.
The amount of lead-in frames is not one alsa period. I can't remember whether I explained the threshold = ALSA_period + mmdevapi_period + safety:
+ mmdevapi_period because at the end of the "buffer processing" period, we still want ALSA to have enough data; + safety(=3-5ms) because our next period callback may come a little late; + ALSA_period because we don't know exactly, but I assume ALSA feels better when it has at least one period in its buffers. For instance, dmix appears to operate on period-size chunks.
That is the minimal amount of frames that ALSA should start with. This is what I want hidden beneath GCP=0. When that much is hidden, ALSA will bear being fed one mmdevapi period of frames at every period callback, i.e. the XAudio2/Rage scenario without underrun (well, disregarding clock shift and timer differences).
You are right that an explicit lead-in is easier to handle than an ALSA start_threshold larger than mmdevapi_period. It's also easier to apply to OSS which knows no such condition.
The lead-in precondition seems to be: if (in_alsa == 0 // does that cover the recover from underrun case? && initial_held_frames < threshold)