- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 8.8k
 
win-asio: ASIO host for obs-studio #12733
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
base: master
Are you sure you want to change the base?
Conversation
b408fbf    to
    763a7f3      
    Compare
  
    4c9de0e    to
    aa3d977      
    Compare
  
    | 
           Update 
  
       | 
    
44c4228    to
    3c02361      
    Compare
  
    | 
           Update 10-19-25  | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like I need to see the code "in action" to better gauge its correctness. I there something like an "ASIO virtual device" or something I can install in my VM and then use this plugin with it?
| /* Copyright (c) 2022-2025 pkv <[email protected]> | ||
| * | ||
| * This file is part of win-asio. | ||
| * | ||
| * This file and all modifications by pkv <[email protected]> are licensed under | ||
| * the GNU General Public License, version 3 or later. | ||
| */ | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RytoEX Should this use the default GPL license header instead?
| void buffer_switch_0(long, long); | ||
| ASIOTime *buffer_switch_time_info_0(ASIOTime *, long, long); | ||
| long asio_message_callback_0(long, long, void *, double *); | ||
| void sample_rate_changed_callback_0(ASIOSampleRate); | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do these need to be hardcoded? This and the use of DEFINE_CALLBACK_SET are unfortunate to me, as we should not use function-like macros at all, particularly not at that complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The context is that the asio sdk was written  while having in mind a host loading a single driver. As in daws.
But of course we need the host to be multidriver. Unfortunately the sdk doesn't pass the 'this' pointer from driver to host.
So it is impossible to know  which driver is calling any given callback.
In order to allow for up to 16 devices, I hard coded the 16 sets of callbacks.
If there is a more elegant solution in plain C,  I am interested !
| bool is_open; | ||
| bool is_started; | ||
| bool driver_failure; | ||
| volatile bool need_to_reset; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of volatile here? Note that volatile doesn't protect against anything, it merely suppresses optimisation by the compiler.
The purpose of the storage modifier was to enable memory-mapped I/O originally, but this doesn't seem to be the case here (as those are just state variables).
If these can be set by multiple threads, then they need to be atomic or need to use a spin lock, mutex, semaphore, etc. instead and then be used without volatile.
See also: https://www.kernel.org/doc/html/v4.17/process/volatile-considered-harmful.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The need_to_reset bool does use our atomics functions (os_atomics_set_bool and os_atomics_load_bool) since it is across threads. The signature of these functions require volatile bools.
See:
https://docs.obsproject.com/reference-libobs-util-threading
My understanding is that this usage is because we use c89 or c99 which don't offer atomics.
An inspection of how these atomics were written will probably reveal they require volatile bool to avoid over aggressive optimizations ?
You can easily check that my usage is consistent with what we do in the rest of the code base, for instance obs-ffmpeg-output.c, etc, where our home-bred atomics always use volatile bools.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is incorrect. A function signature like
static inline bool os_atomic_load_bool(const volatile bool *ptr)does not mean that the pointer passed into has to be volatile qualified, it merely means that the function may accept such a pointer.
If a non-qualified pointer is passed into it, it will automatically be upgraded with the qualification and thus the code pessimisation (no reordering of accesses, explicit loads, no register-based caching) will apply to the function body.
As Linus has pointed out:
the only possible meaning for "volatile" is a purely single-CPU meaning. And if you only have a single CPU involved in the process, the "volatile" is by definition pointless (because even without a volatile, the compiler is required to make the C code appear consistent as far as a single CPU is concerned)
And as far as I can tell the only reason why that function signature carries the volatile is because the functions used on Windows also carry the qualifier:
CHAR InterlockedExchange8(
  [in, out] CHAR volatile *Target,
  [in]      CHAR          Value
);So the actual question that has to be answered here is:
Is need_to_reset changed directly by a hardware I/O register, an external signal or interrupt handler, or between calls to setjmp and longjmp, and consequently also read directly?
Because if neither is the case and all read/write accesses from any thread use the atomic functions, there is no benefit to qualify it as volatile, and instead code pessimisation takes place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok i wasn't aware that the volatile qualifier was not compulsory and would be automatically upgraded.
Currently the bool is used only in our atomics functions in ui thread and in the driver thread, so I assume it is then safe to drop the qualifier.
But the question is then whether it leads to adverse consequences to keep it?
Your observation would then extend to other places to the code base.
I merely followed the current usage without questioning it due to lack of litteracy that i will readily confess, but it seems i am not alone in that respect.
Is the question you ask of great import or just nitpicking ? Honest question.
This adds: - an ASIO Input source, allowing audio capture of devices using Steinberg ASIO audio SDK on windows. This allows low latency capture. - an ASIO output, which will allow routing audio from OBS to any ASIO device. A per channel routing is provided. The UI to setup the ASIO output is provided in a later commit. Signed-off-by: pkv <[email protected]>
This adds an ASIO output entry in Tools Menu allowing to setup audio output from obs to an ASIO device. Signed-off-by: pkv <[email protected]>
On windows, this adds an additional audio track (Track 7) which is used to output a mix of monitored sources. Currently the mixing is left to WASAPI on windows for WASAPI monitoring devices. But ASIO SDK doesn't allow multiple clients (although individual drivers might allow it) and therefore can not mix them. So we have to do the mixing on obs side. Signed-off-by: pkv <[email protected]>
This enables a monitoring track for output. Signed-off-by: pkv <[email protected]>
This adds a QToolButton to the Audio Settings on Windows. This triggers in turn a dedicated settings for the ASIO monitoring output. If no ASIO driver is detected in the system, the panel displays an explanatory message. The panel allows to: - select a monitoring device; - for each output channel of the ASIO device, one can select any channel from any of the 6 tracks or from the monitoring mix. Signed-off-by: pkv <[email protected]>

Description
ASIO is a driver standard developed by Steinberg for low-latency audio. It is commonly used in pro audio.
It was unfortunately not possible for a long time to write a native ASIO host in obs because of license issues.
This has changed thanks to a partnership between the project and Yamaha Steinberg:
https://www.steinberg.net/press/2025/obs-collaboration/
The ASIO sdk is now released under dual licensing, including GPL v3 which is compatible with obs-studio.
Historical aside. When I got involved with obs coding, after working on surround sound support, my first plugin
endeavor was to write an asio source, which was developed eventually in collaboration with Andersama. It was a great learning experience. The ASIO sdk is notoriously tricky with lots of pitfalls for hosts and drivers alike. It was so daunting that at that time (early 2018) we relied on third-party libraries (RTAudio, Bassasio, portaudio) and now JUCE. The last incarnation of our asio plugin for obs (based on JUCE) was mostly coded by Andersama. It has been superseded in many ways by another third-party plugin based also on JUCE, atkaudio which has lot of capabilities but again relies on a third-party library. And anyway our ultimate goal had always been to add support for ASIO into obs.
This PR brings ASIO support in obs-studio natively: no third-party library is used but Steinberg SDK is leveraged directly.
For the host implementation, we have taken cues from JUCE ASIO host which documents a lot of pitfalls.
Our ASIO host provides:
The asio output in turn allows:
Technical note
The asio callback processes both audio from host to device and from device to host at the same time. The main difference with wasapi, is that any monitored audio sent to the device is not automatically mixed; it is the responsibility of the host to do the mixing. That is why asio can not be seamlessly integrated into libobs/audio-monitoring and that we resorted to creating an obs-output for asio.
This output is controlled through a frontend plugin which instead of adding an entry into the tool menu (as is customary) is callable from Settings > Audio alongside monitoring devices (wasapi on windows).
Screenshots:
ASIO source

ASIO source with channel selection

ASIO source with device selection

ASIO monitoring integrated to audio settings

ASIO monitoring panel

ASIO monitoring panel with track channel selection. Not the special monitoring track

Motivation and Context
ASIO brings the following advantages:
How Has This Been Tested?
Tested on windows 11 pro with several asio devices:
Testers are welcome to report their results with their interface and I'll update the list.
Types of changes
Checklist: