Hi,
Maarten Lankhorst wrote:
For capture I plan to just add 2 queues, one for readable packets, and one for packets that can be filled for reading.
Winecoreaudio uses exactly this.
... for the pulse driver, I'm using the auto timing update feature and the callback for when rendering is not running. When the buffer is not underflowed, I'm using the write callback to signal more data is available.
I'm not familiar with PA's API, so I'm not following you. I'm not even sure we talk about the same thing.
I believe the event should be triggered when there is actual data available, at least that's how I understood the event is supposed to work.
I distinguish 2 events: a) ALSA/PA backend ready for more data b) mmdevapi SetEventHandle to the app
Note that b) only exists when using EVENTCALLBACK.
We have tests about b) that show that mmdevapi delivers events to the app even when stopped (Wine fails those with todo_wine). I don't know at what rate.
Regarding a), nothing prevents you from using the back-end's favourite notification mechanism to wake up - or use a timer.
I agree with you that ideally, somehow, b) and a) should be in sync, otherwise we'll have clock skew and the XAudio scenario will exhibit occasional underruns.
But there are big HOWEVER: - ALSA/PA may not grant us the period we'd like (10ms). 21.333ms is common with ALSA/dmix. I don't know how important the 10ms are. You're familiar with DSound, so perhaps you have an opinion why DSound has been using 10ms intervals in Wine regardless of the back-end's period. I believe that Wine ought to use the same rate as native or some app will exhibit a bug.
- We do not need 10ms events when not using EVENTCALLBACK, so why not write all available data (e.g. 333ms from winmm:PlaySound) and sleep that much? Laptop owners will thank us.
- How to continue signaling type a events after IAudioClient_Stop? By continuing to write silence to the back-end?!?
- Last but not least, I don't know whether ALSA's signaling and mmdevapi's SetEvent needs can be made compatible even when the periods would agree. mmdevapi's SetEvent means "don't worry, you have one period time to write data" or even "you may write data, but I already have buffered some". ALSA/PA's signal means(?) "hurry up, you're on the verge of underrun". Please correct me.
- The test_worst_case aka. XAudio scenario has tough requirements: - Signal events not often enough and you'll enter an underrun. - Signal events too early and it'll write no data. The event was wasted and the next one may come too late to avoid an underrun.
In summary, if the back-end guarantees 10ms wake-ups, you should be able to nicely sync a) and b) (probably by writing silence when stopped...) If not, then some mechanism must be there to decouple the two.
So far we've followed the "decouple" route in winealsa/oss. I believe the key to the solution in mmdevapi will come from both being able to vary the sleeping intervals to adapt to clock skew *and* not be bound to be exactly in sync with the back-end, thanks to a latency-inducing buffer large enough to compensate for the variability. IOW, the design goal is to reach during normal playback a state where: Event received => GetCurrentPadding has (or pretends to have) decreased by at least 1 period (which implies there's room for writing).
Regards, Jörg