Replies: 20 comments 3 replies
-
|
Hi - I have previously reported #937 . Have you tried Jack on windows? Jack seems like the only real option to get latency down for your use case on windows. Wasapi, dx or other backends just won't cut it - not because of miniaudio, but because of underlying libraries & drivers. I know Jack is not ideal - your users would need to install and configure Jack. But realistically, other than ASIO (which doesn't seem to be supported by miniaudio), this is the only way to make windows play along. I've had some success with Jack. Essentially, what works for me is configuring Jack to use ASIO backend (my audio interface has a native ASIO low-latency driver). You could use ASIO4ALL drivers instead - I've found ASIO4ALL works quite well. You can then set Jack latency very low and you should be able to get down to reliably working at ~5ms. That is, unless @mackron adds ASIO backend... |
Beta Was this translation helpful? Give feedback.
-
|
Hi almostobvious, interesting question about Jack on windows, just know this from the linux ecosystem. To my understanding of what I just red about ( https://jackaudio.org/faq/jack_on_windows.html ) it's just another abstraction on the windows infrastructure (WASAPI or ASIO etc.). Have meanwhile tested with Debug output active. It claims "Trying IAudioClient3', but minPeriodInFrames is 480 frames that correspond to 10ms buffer, this is not low latency. Have found a docking station with a USB-2 connected chipset (using the standard Windows driver that (as far as I understand is IAudioClient3 enabled. This is only a reduction from 480 to 336 frames! I don't know why exactly 336 frames. I set the flag deviceConfig.noFixedSizedCallback to true, but at least on debug output I can not see any improvements: still 336 frames (or 336*3 = 1008 buffer size, this might as I understood only deactivate some MA-internal Buffering (that is needed to have equal sized buffers in the callback. As said, I believe the root cause it missing driver support in Windows likely, so if someone has recommendation for a consumer grade-audio product that is supported by a (build in) driver for 128/64 or 32 frames buffer under windows? |
Beta Was this translation helpful? Give feedback.
-
|
I think what you are seeing there is miniaudio's "version of the truth". Wasapi will have additional internal buffering which is the cause of latency (not miniaudio). As far as I can tell, miniaudio can't change or even see this as it's not necessarily visible in the underlying API. I am also thinking about how to make Jack a bit more usable for my app's end-users. I am experimenting with bundling jack in my installer and launching jackd on startup. On linux it's much easier, just install jackd with apt/dnf and follow these instructions. On windows it's a bit more involved it seems. |
Beta Was this translation helpful? Give feedback.
-
|
So IAudioClient3 is for what Microsoft calls "low latency shared mode". If you need the lowest possible latency you can try using exclusive mode. There is a config option for it in the device config. Should be named "playback/capture.shareMode". Note however that I haven't done as much testing with exclusive mode than shared mode so I'm not sure stable it is. Would be interested in feedback. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks so much for the input, @mackron. I'm quite new to windows audio subsystem and learning new every day. This looks like direct calls to WASAPI to me. The framerate comes directly from the call to GetSharedModeEnginePeriod, that returns this (not so) low latency framerate, so all coming directly from windows (or respective drivers). As of the exclusive mode it's maybe worth a try. Microsoft has some documentation here: Th shared mode would be prefered, but if it's significant faster .... in the initial shared Microsoft Link it's mentioned ASIO makes use of it.... maybe for a reason. Nice to have it even already in miniaudio, I read the exclusive mode is not only limiting to exclusive one program accessing the sound card, but also thread priority of audio thread etc. need to be done all manual. |
Beta Was this translation helpful? Give feedback.
-
|
As suggested I had a very quick first check of the exclusive mode by just adding: Miniaudio seems to accept all requested buffersize I requested. I tested 128 frames and 64 frames. On some device the output is good at first, or I just have a sound of some frame drops. In general after some minutes later the sounds completely strange. I'm guessing the audio tread and the midi receiving thread getting out of sync. (I'm using a lock free ringbuffer and atomic operations to keep both in sync. Not sure this is driver/hardware/miniaudio or simply my own program bug. Debug output: As I have tested USB-Audio devices as well I get DEBUG output when just removing the dongle. Assuming exclusive mode can help to really get below 10ms latency as the buffer size indicate and when getting the audio glitches fixed, it could be an option. |
Beta Was this translation helpful? Give feedback.
-
|
One experiment you could try is modifying the simple_playback example to use exclusive mode, and then run it with a long sound like a song and see if that also results in broken audio after some time. That would narrow it down a bit. If that is also not working then it would almost certainly be a bug in a miniaudio. I do remember when I first implemented support for exclusive mode that it was very fiddly. It would not surprise me at all if there's some subtle errors in there. As for JACK, surely that would just be sitting on top of WASAPI. If they can do proper low-latency then miniaudio should be able to as well. I would bet JACK uses exclusive mode. A few more considerations off the top of my head. No idea if these would have any impact, but maybe worth a mention:
|
Beta Was this translation helpful? Give feedback.
-
|
this are good hints, I'll check them out. Meanwhile I have played with my latency measurement program and played with exclusive mode. As baseline (internal sound card) Requested buffer size is 128 frames. Switched to a USB 1.0 external speaker: |
Beta Was this translation helpful? Give feedback.
-
|
As I'll be busy next days just some updates on my testing progress: I tested the some options proposed by @mackron , and what made a huge difference is MCSS is the Multimedia Class Scheduler Service, to my understanding responsible for thread scheduling and putting this magic "Pro Audio" in boosts the thread priority significantly, what results in my case to remove audio glitches (almost). I write almost as after really quite longer time like 20-30 minutes some inconsistency, but this might be at least in one case of getting the laptop into power saving or playing with various audio devices (unplug USB etc). However this flag did not resolve the strange 120ms latency in exclusive mode reported earlier.
Both have all update installed and report both a Realtek chipset. Here the measurement indicate much better latency on the old Hardware: Capture/Recording in Shared: about 45 ms (similar to new Windows 11 measurements) Running on the old Windows 10 hardware easy on 64 frames. While modern windows 11 system has very high latency. |
Beta Was this translation helpful? Give feedback.
-
In my tests on windows, Jack was only able to hit low latency (<10ms) using ASIO backend. @mackron - would you be interested in putting together an ASIO backend for miniaudio? I thought I'd give it a go, but don't want to duplicate the effort if you are already considering it. |
Beta Was this translation helpful? Give feedback.
-
|
First cut ASIO types brought into miniaudio.h below. @mackron - any comments on naming conventions / style before I dive into implementing backend? |
Beta Was this translation helpful? Give feedback.
-
|
I'm very interested in the existence of an ASIO backend, and I'm not currently developing one. But I'm questioning whether or not I want to have it built into miniaudio.h directly. I would rather the built-in backends be for fundamental OS-level backends like WASAPI, ALSA, Core Audio, etc. I'm thinking I'd rather it be a self-contained custom backend that could be put into the extras folder. Your best bet would probably be to base it off the dev-0.12 branch because that has some changes to the custom backend system, the most important of which is that backends can now be entirely modular (the current system is kind of bad and not very pluggable). I can give you some guidance on how that works if you need it. The dev-0.12 branch has an SDL2 custom backend you could use as a reference as well. For a backend like ASIO, I'd rather just use the official SDK and skip the dynamic linking stuff entirely to be honest. It's an annoying maintenance burden. I know I do this in miniaudio.h, but it's kind of different there because they are part of the main library and there's a lot of backends to deal with which would put a massive burden on the build process for everyone who uses the library. But when the backend is opt-in like this it doesn't affect every single user of the miniaudio, and therefore I just don't care as much, and I think from a cost vs benefit point of view it's not worth it. |
Beta Was this translation helpful? Give feedback.
-
Makes sense. You really feel the overhead when compiling on something slow like raspberry pi (until I got my wits about to pick a single backend). I didn't have a chance to take a closer look at dev-0.12 branch yet, will give it go this weekend. |
Beta Was this translation helpful? Give feedback.
-
|
ASIO sound very interesting interesting indeed. I'm interested what @almostobvious will come up with! I like the way miniaudio is dynamic loading all OS-standard function on the respective system. Have reimplement similar for my midi-stack, so I can completely understand the mandnes (and goodness) .... :-) Considering ASIO ideally needs Steinbergs SDK and I don't know what kind of license questions this might raise, might be indeed an advantage to implement it as independent backend or maybe separate project even (??): I'm a developer not a lawyer. As I was searched in internet I come across about the following piece of documentation on a project called FlexASIO This particular ASIO driver is implemented on PortAudio and thus has access to many backend. It seems under windows with "kernel mode streaming" one can get even one more step closer to the metal (WDM driver in kernel mode). Seems quite a bunch of ASIO driver use "kernel mode streaming" (and FlexASIO provides it indirect). Just checked how PortAudio actually achieves kernel mode streaming. It's just one file of about 6k lines of windows kernel madness.... I'm not sure kernel mode stream could potentially have any advantage to WASAPI exclusive mode in terms of latency reduction. As I have a little portaudio experience (on mac) maybe I put together some test-program to verify the available backends. However as miniaudio fan so just for testing. :-)
|
Beta Was this translation helpful? Give feedback.
-
|
Yeah for something like ASIO I think it'd be best to just use the SDK and be done with it. Like I said in my earlier comment, in my opinion runtime linking is great for things that affect the build system of every user, but for an opt-in thing like ASIO it's not a big deal. @almostobvious If you are indeed serious about doing an ASIO backend by all means feel free to reach out to me during development if you feel the need. I have no experience with ASIO, but I can certainly help with the miniaudio related stuff. For the 0.12 release I'm hoping to have backends in there for SDL3, PipeWire and Oboe. I'd be more than happy to add ASIO as well if you also want to. @fritzsche I'm aware of the kernel mode stuff, but I thought it would be basically redundant with WASAPI's exclusive mode. I really don't want to be doing a kernel mode backend. |
Beta Was this translation helpful? Give feedback.
-
|
Meanwhile I have applied the recommended function call, but still see this audio failure after some minutes. HW: Premium Laptop / USB 1.1 audio device using standard Microsoft USB Audio Driver. Have observed similar issue on other (Consumer grade) USB audio device. No significant load on the system in Task Manager. The source code has ma_wasapi_usage_pro_audio commented out, as the glitches start earlier. Applying the "Pro Audio" increase thread priority and let the same problem happen just later. Have tested also with buffer size of 128 frames, what is little better again, but issue happens as well with 128. Observation: Compile having miniaudio.h in same directory. I'm using mingw-w64 compiler. My main program is outputting a rhythmic sound, that gets slower and distorted. In the pause between the beat I output 0 and there is no distortion of this. This could be that I'm hitting a hardware limitation or other limit of driver/windows as I force way smaller buffer size than shared more would allow me. #define MA_NO_DECODING
#define MA_NO_ENCODING
#define MINIAUDIO_IMPLEMENTATION
#define MA_DEBUG_OUTPUT
#include "miniaudio.h"
#include <stdio.h>
#define DEVICE_FORMAT ma_format_f32
#define DEVICE_CHANNELS 2
#define DEVICE_SAMPLE_RATE 48000
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
ma_waveform* pSineWave;
MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS);
pSineWave = (ma_waveform*)pDevice->pUserData;
MA_ASSERT(pSineWave != NULL);
ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL);
(void)pInput; /* Unused. */
}
int main(int argc, char** argv)
{
ma_waveform sineWave;
ma_device_config deviceConfig;
ma_device device;
ma_waveform_config sineWaveConfig;
ma_context context;
ma_context_config context_config;
context_config = ma_context_config_init();
context_config.threadPriority = ma_thread_priority_realtime;
if (ma_context_init(NULL, 0, &context_config, &context) != MA_SUCCESS)
{
printf("Failed to initialize the audio context.\n");
return -1;
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = DEVICE_FORMAT;
deviceConfig.playback.channels = DEVICE_CHANNELS;
deviceConfig.sampleRate = DEVICE_SAMPLE_RATE;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = &sineWave;
//************************************************************************* */
// activate share mode
// set audio buffer very tiny
deviceConfig.playback.shareMode = ma_share_mode_exclusive;
//deviceConfig.wasapi.usage = ma_wasapi_usage_pro_audio;
deviceConfig.noPreSilencedOutputBuffer = MA_TRUE;
deviceConfig.noClip = MA_TRUE;
deviceConfig.noFixedSizedCallback = MA_TRUE;
deviceConfig.periodSizeInFrames = 64;
//************************************************************************* */
if (ma_device_init(&context, &deviceConfig, &device) != MA_SUCCESS) {
printf("Failed to open playback device.\n");
return -4;
}
printf("Device Name: %s\n", device.playback.name);
sineWaveConfig = ma_waveform_config_init(device.playback.format, device.playback.channels, device.sampleRate, ma_waveform_type_sine, 0.2, 220);
ma_waveform_init(&sineWaveConfig, &sineWave);
if (ma_device_start(&device) != MA_SUCCESS) {
printf("Failed to start playback device.\n");
ma_device_uninit(&device);
return -5;
}
printf("Press Enter to quit...\n");
getchar();
ma_device_uninit(&device);
(void)argc;
(void)argv;
return 0;
}Debug output:
|
Beta Was this translation helpful? Give feedback.
-
|
For verification I created also a program using portaudio, with the following result.
This measurements rather indicate a limitation of the hardware or Windows or driver, and seems to be not a problem with the audio library. |
Beta Was this translation helpful? Give feedback.
-
|
Just for reference on people trying to get audio out of Windows 11. Meanwhile I have testes on a real audio interface Motu-M2 (that in general known to be capable of low latency), but had regular audio glitches (frame drops) (every 1-2 minute) even on relative large buffer size (Win 11 23H2). (disclaimer: WDM, no ASIO). Upgrade to Win 11 24H2 made situation woers, and I got blue screen. As the "consumer USB audio dongle" keep on working, this might be a HW issue on the Motu or some driver issue. The consumer USB dongle seems to work better with win 11-24H2: have USB 1.0 running directly on the device seem to take longer until the audio distortion happen. The strange behaviour that build in Audio card has a lot of latency (even worse on Exclusive mode) is still the same on 24H2. On a thunderbolt dock internal (USB 2.0) audio interface however, I could not reproduce the error on exclusive mode and latency seems to be acceptable. All fine! As mentioned above: it's not a miniaudio issue, but a HW/Driver/Windows problem. |
Beta Was this translation helpful? Give feedback.
-
|
Converting this one to a discussion just to clean up the issue tracker a bit. Also, the dev-0.12 branch has a bit of a refactor of the WASAPI backend. Don't think it'll affect this at all, but figured might be worth mentioning. |
Beta Was this translation helpful? Give feedback.
-
|
So I ran a duplex test in exclusive mode for both the capture and playback sides, and I was able to run it for 30 minutes without it ever getting into a distorted state. That was with the playback side being some headphones plugged into my motherboard jack, and a USB microphone for the capture side. For playback, the lowest period size I could get was 128 frames at 48K, which if my math is correct translates to about ~2.6ms. On the capture side, I was able to get down to 144 frames, or 3ms. If I push it any lower I changed some of the logic for determining the buffer size for exclusive mode. Previously it would try the size requested in the device config, and if that failed it would double it and then try again. Now I first query On the low-latency shared mode side, I was able to get my playback device down to 128, which is consistent with exclusive mode, but for my microphone it was stuck at 480. I think low-latency shared mode is just very device/driver specific. This testing was in the dev-0.12 branch. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Dear Mackron, Dear Community,
I'm using miniaudio for a latency critical application. It received midi-messages and produce audio.
The app was developed for Mac/Linux/Windows, to miniaudio it the perfect choice.
I didn't realized an issue as mac/linux are main dev. system, but on windows I realized really bad latency. This was reported here too:
#937
But issue closed as Linux worked out ok.
I created a tiny latency measurement program with miniaudio: plays sounds and records the output.
Result:
Mac: 1ms,,
Windows 10: 83ms
Windows 11: 93ms.
Windows is using WASAPI both are laptops with a Realtek chipset.
https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio
Explaines < 10ms latency should be possible using IAudioClient3. However IAudioClient3 seems to be not supported and the "generic microsoft driver" does not work for my Realtek chip.
I recognized miniaudio is reporting the internal buffer frames of 480 (10ms) (even I request 128 or lower), what is standard on old (non IAudioClient3) based implementation of WASAPI.
So likely the latency issue I observe it not a miniaudio bug but a general issue with windows and respective audio driver.
As I only have laptop computer, I'm looking for budget USB based audio interface that has IAudioClient3 and low latency (small frame buffer size like 128/64/32 frames).
Searched the internet, but could not find a reliable source of information what USB audio interface is supporting low latency with WASAPI (ideally with microsoft standard driver). Most I found was for Steinbergs ASIO.
Thanks!
Thomas
Beta Was this translation helpful? Give feedback.
All reactions