http://bugs.winehq.org/show_bug.cgi?id=28723
--- Comment #102 from Jörg Höhle hoehle@users.sourceforge.net 2011-12-19 16:39:28 CST --- Well, I came to the conclusion that Alexey's is really 2 patches and should be split: one to have GCP implement delta increments and be updated only when write happens at event ticks, the other to limit the writes. As I said in comment #83, I don't like the alsa_write rate limiting part. Furthermore, I think that part would be strictly superfluous if set_hw_periods(3) or (4) gives good results.
To summarize set_period_near(mmdevapi_period) set_periods(4)
if(some_test) return INVALID_PERIOD_SIZE (excl.) or CREATE_ENDPOINT_FAILED (shared). if(other_test) FIXME("period size doesn't match, expect trouble").
To recap:
Why do we need a not too large buffer? a) Because PA appears to work better and b) because snd_pcm_drop upon Stop is bogus, so my next patch is going to drop it and let Stop enter XRUN state. So it's essential that ALSA didn't buffer too much, otherwise ALSA would continue to play for too long after Stop. After Stop In shared mode mmdevapi must hold: sum written = GetPosition + GetCurrentPadding
Can the driver deal with an ALSA period < 10ms? We'll feed it only every 10ms, hence we need a buffer large enough to hold more periods. This conflicts with the above set_periods(4), e.g. imagine ALSA period were 1ms. I've not yet tested how set_buffer_min(2xmmdevapi_period) + set_periods(4) play together. Perhaps: alsa_period = mmdevapi_period; set_period_near(alsa_period) // that's an in+out variable! if(alsa_period>=mmdevapi_period) set_periods(4); else set_buffer_size_near(4xmmdevapi_period); This supposes that set_period_near immediately returns a period, i.e. before set_hw_params().
Can the driver bear an ALSA period > 10ms? IMHO only with a silence lead-in patch. The worst-case scenario is: app writes 10ms at every event, but unlike Rage2 doesn't even prefill with 10ms. This is a slight variation of Alexey's test case from comment #55. I claim that this would work in native without underruns. Imagine a 50ms period. Only the silence lead-in gives enough freedom in streaming mode such that after 5x10ms have been sent, ALSA won't XRUN just before the next 5x10ms have been collected and sent. Currently I'm not sure whether a 10ms lead-in is enough, or a 40-50ms one required.
Furthermore, because of the bug in comment #69 that ALSA won't play a trailing chunk less than period size, we also need to write trailing silence... A trailing silence doesn't make the lead-in superfluous. I'd believe native can get away with a lead-in because its mixer (behaves as if it) is constantly running, but it still needs trailing silence to eventually have the HW play the final bits. Wine needs the lead-in because its mixer is not running and sending a continuous audio stream. So it's not so funny that we're back at the original wine-1.3.25 mmdevapi design which used to add silence, except that we now know better - that GetPosition must filter out our silence additions and - that it's incorrect to add more than mmdevapi 10ms silence at each event, even with ALSA period size 50ms.