Maarten,
- hres = IAudioClient_GetStreamLatency(device->client, &period);
device->sleeptime = period_ms * 5 / 2;
ret = WaitForSingleObject(dev->sleepev, dev->sleeptime);
Although it's a minor point, as we're solely discussing the case of the timeout when mmdevapi doesn't call SetEvent, I wonder why you insist on using GetStreamLatency as the basis of your timeout computations instead of GetDevicePeriod.
You know that wineXYZ.drv use the device period as the basis for their SetEvent, thus IMHO the timeout too should be based on it, instead of a GetStreamLatency we know next to nothing about.
If you visit testbot jobs 23521 and 23514, you'll see that I've measured the event rates. Sadly, all testbot VMs report a GetStreamLatency of 10.6666ms too close to the DefaultPeriod of 10.0000ms to tell for sure which is used as the average period.
W7 and w2k8 machines seem to use DefaultPeriod: render.c:185: Returned periods: 10.0000 ms 3.0000 ms render.c:333: Returned latency: 10.6666 ms render.c:626: event after Start average 10.004ms render.c:2206: event average 9.992ms sigma 0.447
Vista may use its reported StreamLatency as period: render.c:185: Returned periods: 10.0000 ms 3.0000 ms render.c:333: Returned latency: 10.6666 ms render.c:626: event after Start average 10.697ms render.c:2206: event average 10.736ms sigma 0.834
The one w2k8 machine is peculiar as it appears to use the 15.600ms (or 15.625ms?) timers well known from pre-Vista times: render.c:185: Returned periods: 10.0000 ms 3.0000 ms render.c:333: Returned latency: 10.6666 ms render.c:626: event after Start average 15.547ms render.c:2206: event average 15.625ms sigma 5.625
However, the rate is certainly not the 20-30ms StreamLatency that e.g. winealsa returns.
Regards, Jörg Höhle
Op 21-12-12 11:59, Joerg-Cyril.Hoehle@t-systems.com schreef:
Maarten,
- hres = IAudioClient_GetStreamLatency(device->client, &period);
device->sleeptime = period_ms * 5 / 2;
ret = WaitForSingleObject(dev->sleepev, dev->sleeptime);
Although it's a minor point, as we're solely discussing the case of the timeout when mmdevapi doesn't call SetEvent, I wonder why you insist on using GetStreamLatency as the basis of your timeout computations instead of GetDevicePeriod.
You know that wineXYZ.drv use the device period as the basis for their SetEvent, thus IMHO the timeout too should be based on it, instead of a GetStreamLatency we know next to nothing about.
If you visit testbot jobs 23521 and 23514, you'll see that I've measured the event rates. Sadly, all testbot VMs report a GetStreamLatency of 10.6666ms too close to the DefaultPeriod of 10.0000ms to tell for sure which is used as the average period.
<snip>
Because I'm using it later on in the rework to tell how much to queue. In my rework, I try to write at most 3 * GetStreamLatency, so even if for some reason no event is ever delivered, you would never get an underrun.
This is why I choose streamlatency instead of getdeviceperiod. Also since it may be a different value, who says it's only going to be bigger than the default period? It could theoretically be smaller, still..
~Maarten
Hi,
Maarten Lankhorst answered:
[...] I wonder why you insist on using GetStreamLatency as the basis of your timeout computations instead of GetDevicePeriod.
Because I'm using it later on in the rework to tell how much to queue.
Ah. But why not use the correct tool for the correct job? GetPeriod for period, and StreamLatency for buffer and queue sizes?
In my rework, I try to write at most 3 * GetStreamLatency, so even if for some reason no event is ever delivered, you would never get an underrun.
I'm sorry to disagree, but I've conducted numerous tests last night. The results are very disappointing, but I'll only find time in January to write more about it.
Basically, no trick in DSound or Winmm whatsoever can prevent an underrun. The typical Linux machine can and will not schedule arbitrary threads that are ready to run, and I observed arbitrary pauses of 12-120ms. :-(
How much was wake up delayed? For lovers of histograms: sort -n delays | uniq -c period 20ms 10ms 57 0 828 0 41 1 202 1 2767 2 2771 2 541 3 185 3 258 4 1956 4 6 5 16 5 22 6 13 6 5 7 1 7 1 8 10 8 2 9 2 9 11 10 3 10 4 11 1 12 9 12 1 13 1 13 2 14 1 16 1 18 1 34 1 88 1 119 3716 samples 6005
- Even if mmdevapi SetEvent's your thread, there's no guarantee that it gets scheduled without or with little delay. - Above data is for one thread. As multiple threads are involved in producing audio, delays accumulate. - Even if the DSound thread always gets to run and Release's data, there's no guarantee that the winealsa.drv thread does and sends data to ALSA. - Worse, even if the winealsa thread gets to run, there's no guarantee *AT ALL* (and I've seen it happen) that it won't lose CPU for over 20ms even if calling nothing but snd_pcm_* (and TRACE) in the callback.
As a consequence, the current winealsa.drv can, by design (ALSA buffer holding no more than 3 periods), not prevent underruns, no matter how much you kick it.
You advertised RT priorities. With them, the picture would look different of course. A faster machine helps too...
In January, I'll write more, e.g. about concrete changes in code.
BTW, yesterday I replaced the timer queues in winealsa with an own thread. Timing is much better, but that doesn't prevent delays. More changes are needed to improve the situation.
Regards, Jörg Höhle
Op 21-12-12 18:44, Joerg-Cyril.Hoehle@t-systems.com schreef:
Hi,
Maarten Lankhorst answered:
[...] I wonder why you insist on using GetStreamLatency as the basis of your timeout computations instead of GetDevicePeriod.
Because I'm using it later on in the rework to tell how much to queue.
Ah. But why not use the correct tool for the correct job? GetPeriod for period, and StreamLatency for buffer and queue sizes?
Because the timeout is not meant to be something that normally should ever be hit normally, it's just an upper bound on how long we would be prepared to wait in case something does mess up.
In my rework, I try to write at most 3 * GetStreamLatency, so even if for some reason no event is ever delivered, you would never get an underrun.
I'm sorry to disagree, but I've conducted numerous tests last night. The results are very disappointing, but I'll only find time in January to write more about it.
Basically, no trick in DSound or Winmm whatsoever can prevent an underrun. The typical Linux machine can and will not schedule arbitrary threads that are ready to run, and I observed arbitrary pauses of 12-120ms. :-(
How much was wake up delayed? For lovers of histograms: sort -n delays | uniq -c period 20ms 10ms 57 0 828 0 41 1 202 1 2767 2 2771 2 541 3 185 3 258 4 1956 4 6 5 16 5 22 6 13 6 5 7 1 7 1 8 10 8 2 9 2 9 11 10 3 10 4 11 1 12 9 12 1 13 1 13 2 14 1 16 1 18 1 34 1 88 1 119 3716 samples 6005
- Even if mmdevapi SetEvent's your thread, there's no guarantee that it gets scheduled without or with little delay.
- Above data is for one thread. As multiple threads are involved in producing audio, delays accumulate.
- Even if the DSound thread always gets to run and Release's data, there's no guarantee that the winealsa.drv thread does and sends data to ALSA.
- Worse, even if the winealsa thread gets to run, there's no guarantee *AT ALL* (and I've seen it happen) that it won't lose CPU for over 20ms even if calling nothing but snd_pcm_* (and TRACE) in the callback.
As a consequence, the current winealsa.drv can, by design (ALSA buffer holding no more than 3 periods), not prevent underruns, no matter how much you kick it.
It's holding 8 periods, it just refills a maximum of 3 periods at a time. With a timeout upper bound of 2.5 periods, it would keep up on average even if nothing is moving forward..
You advertised RT priorities. With them, the picture would look different of course. A faster machine helps too...
I never looked at winealsa, I'm scared by the memory allocations in dsound inside the mixer thread, instead of just allocating some upper bound, so I never wanted to see closely at how the rest of the stack behaves..
Not sure what winealsa thread is actually doing, but it should really just do as little as possible, and if it keeps any locks, all other paths that could end up taking the same locks should be audited in a similar way with suspicion.
Even if it's not actually elevated to rt , it should act as though it is, since any improvements also benefit upper bound without -rt..
In January, I'll write more, e.g. about concrete changes in code.
BTW, yesterday I replaced the timer queues in winealsa with an own thread. Timing is much better, but that doesn't prevent delays. More changes are needed to improve the situation.
It would also be interesting if you have any suggestions on how to improve winepulse, and if there are still outstanding differences wrt to native mmdevapi. With that latency fix I may look into enabling exclusive mode again, as it was probably hit extra hard by that pulseaudio bug.
~Maarten