-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Audio glitches with default settings (DirectSound gets stuck) #29
Comments
Ok, I managed to reproduce it using REW 5.19. Indeed it's a pretty obvious bug, sorry about that; I'm sad that I didn't catch it earlier. I will investigate further, but I'm not sure I'll have time to fully resolve this before next week. In the mean time, I noticed the following configuration seems to solve this problem, so feel free to use that as a workaround: [input]
suggestedLatencySeconds = 0.100
[output]
suggestedLatencySeconds = 0.100 This would make this a regression from 8cfb77e, first released in FlexASIO 1.0. It looks like my rationale was wrong in this change. |
flexasiotest.txt Three diagnostic files attached |
For some reason, only the first 20 stream callbacks (i.e. the first ~400 ms) occur. Then the stream callbacks just stop firing. This is completely consistent with the issue we're observing, including the fact that the audio doesn't stop (the same buffer is being played indefinitely). I can even reproduce this in FlexASIOTest if I increase the number of buffer switches it's waiting for. This should never happen no matter what FlexASIO does and no matter what the settings are. This is starting to smell like a PortAudio bug. It happens with PortAudio With the MME backend there appears to be glitching as well, but it's still firing stream callbacks, so that's probably a different issue. Filed #30 to track that. Next step is to figure out where in PortAudio code the streaming loop gets stuck. |
Let me know if I can assist in any testing.
|
Another interesting observation is that this only occurs in full-duplex mode. If either the input or the output is disabled, I can't reproduce. Also this doesn't seem to be an actual deadlock within PortAudio. The internal PortAudio polling event is firing, but PortAudio decides not to call the stream callback. In Looking at the business logic involved, it looks like one way this could happen is if the input or output buffer fill level never reaches the user buffer size. Specifically, it might be that there is not enough valid data (i.e. at least 20 ms, with the default settings) in the DirectSound host buffer when polling occurs. My understanding of the logic is that this is expected to happen from time to time, and that the buffer fill level should eventually reach the point where stream processing can continue. But in practice that doesn't seem to happen, and as a result stream processing grinds to a halt. This is further complicated by the fact that the DirectSound host buffer is a circular buffer, and PortAudio doesn't seem to insert any intermediate buffer - it's a straight copy from the DirectSound buffers and the user (ASIO) buffers. This means that we can get into a situation where, if it takes too long to consume/produce data from/to these buffers, it might be too late and we've wrapped around the circular buffer again. (Looking at This is made even more precarious by the fact that this is full duplex operation, which means both the input and output buffers need to get to the correct fill level at the same time for things to work. In theory, PortAudio is supposed to set the polling frequency and host buffer sizes in such a way that we don't get into that kind of catch-22 situation, but it might be that the default FlexASIO settings, which result in a ~40 ms host buffer size and a ~5 ms polling frequency, might be too stringent for this to work. This might be further compounded by the fact that I suspect DirectSound doesn't actually have a 5 ms granularity when it comes to buffer span validity. |
Some more data from experiments: with default settings, 44.1 kHz sample rate, stereo input and output, the DirectSound capture buffer size is set to 7232 bytes (41.0 ms). Polling occurs every 5 milliseconds or so. Every time polling occurs, Meanwhile, the current PortAudio read offset into the buffer is stuck at 5472 bytes (31.0 ms). If the returned read position was zero, PortAudio assumes that it can read from the last 1760 bytes (10.0 ms) of the buffer (wraparound). If the read position was 5512, PortAudio assumes it can read from a span of 40 bytes in the middle of the buffer. In both cases, the read is not large enough to fill the 20 ms user buffer, so PortAudio simply waits for the next poll for more data to become available. On the next poll, the exact same scenario repeats itself, and the whole loop gets stuck. |
Using a forcibly reduced polling period in PortAudio still results in This also occurs when disabling the output side, but then PortAudio doesn't get stuck. Presumably that's because its read offset doesn't get wedged in that case, since the output position doesn't influence it. The read cursor granularity on the output side is around 9 ms, which is much better. Therefore it would seem that the issue is truly with the way DirectSound handles the input side internally. The DirectSound input read cursor granularity is 31.25 ms. For things to work correctly the DirectSound host buffer size needs to be at least twice that. PortAudio sets the host buffer size to the user buffer size, plus the preferred latency (or the user buffer size, whichever is greater). With the default FlexASIO settings, that results in a 40 ms host buffer, which is too small. If the default FlexASIO buffer size was increased from 20 ms to 40 ms, that would result in a 80 ms host buffer, which would take care of the immediate problem. |
Observing the Windows API calls using the excellent API Monitor sheds more light on the issue. DirectSound uses WASAPI internally; it even goes through the public WASAPI API just like any other application. (That's not surprising, but it's nice to have confirmation.) When calling |
Strike my last - it looks like I misread the interaction between DirectSound and WASAPI. DirectSound is, in fact, transferring data between the WASAPI buffer and the DirectSound buffer in 10 ms (441 samples) chunks, in both directions. Specifically, on capture, WASAPI provides DirectSound with 441 sample buffers through With that in mind, one would expect DirectSound to provide a 10 ms cursor granularity. That's true for the render side, but for the capture side, strangely, that doesn't seem to be the case. Specifically, DirectSound doesn't seem to update the read cursor position it exposes to the application every time WASAPI provides it with an additional 10 ms buffer. This looks like a weird limitation of DirectSound, where it's incapable of providing a capture read cursor granularity of less than 30 ms even though WASAPI itself feeds it 10 ms buffers. |
With this change FlexASIOTest can be used to reproduce #29.
FYI I reported the root cause upstream in PortAudio/portaudio#775 (better late than never!) |
I had the same problem as AustinJerry did in the REW thread at AVS forum. He stated it as such:
"After installing and selecting FlexASIO in the REW Settings panel, the only output options in the drop-down are “out 1” and “out 2”. When I selected out 1 and initiated a signal using REW’s tone generator, there was a brief tone from the left speaker which then changed to a distorted tone which I could not stop without exiting REW completely."
I created a log file per your request to Jerry and have attached it here.
FlexASIOlog.zip
The text was updated successfully, but these errors were encountered: