Search code examples
macosaudiocore-audioiokitdriverkit

MacOS custom Audio Driver doesn't override the default Driver


We are developing a custom audio driver for a USB microphone in order to do simple processing (EQs) on the input audio stream (comparable to an APO for Windows). After some help, we managed to assign our Driver (based on the SimpleAudioDriver) to the right audio device. But we now have two devices showing up : one is assigned with our driver and the other one is assigned to the default driver. How can we override the original one with ours, to just have one device showing up ?

We already tried to add more IOKitPersonalities to have a better probe score but it's the same. We also read the logs and the original driver and our probe score are both at the maximum (100000).

Here is the current state of our info.plist file :

<plist version="1.0">
<dict>
    <key>IOKitPersonalities</key>
    <dict>
        <key>SimpleAudioDriver</key>
        <dict>
            <key>idProduct</key>
            <integer>49456</integer>
            <key>idVendor</key>
            <integer>1130</integer>
            <key>CFBundleIdentifier</key>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
            <key>IOClass</key>
            <string>IOUserService</string>
            <key>IOMatchCategory</key>
            <string>SimpleAudioDriver</string>
            <key>IOProviderClass</key>
            <string>IOUSBDevice</string>
            <key>IOResourceMatch</key>
            <string>IOKit</string>
            <key>IOUserAudioDriverUserClientProperties</key>
            <dict>
                <key>IOClass</key>
                <string>IOUserUserClient</string>
                <key>IOUserClass</key>
                <string>IOUserAudioDriverUserClient</string>
            </dict>
            <key>IOUserClass</key>
            <string>SimpleAudioDriver</string>
            <key>IOUserServerName</key>
            <string>com.example.apple-samplecode.SimpleAudio.Driver</string>
            <key>SimpleAudioDriverUserClientProperties</key>
            <dict>
                <key>IOClass</key>
                <string>IOUserUserClient</string>
                <key>IOUserClass</key>
                <string>SimpleAudioDriverUserClient</string>
            </dict>
        </dict>
    </dict>
</dict>
</plist>

If you have any hints, please get back to us.

Thanks.


Solution

  • The sample driver doesn't match any real hardware, but instead attaches itself to the dummy "resources" nub:

                <key>IOProviderClass</key>
                <string>IOUserResources</string>
    

    This is a generic object that does nothing other than exist so that virtual drivers can attach. By default, objects can only be successfully be matched by one client (i.e. driver), so virtual drivers would fight over access to this dummy object. So when matching this object only, you need to use match categories:

                <key>IOMatchCategory</key>
                <string>SimpleAudioDriver</string>
    

    However, you must absolutely not use this key when matching real hardware, unless you have a very good reason. If you keep this in, your driver's match category will be different from Apple's default driver, so both will match the device, leading to chaos.

    To avoid multiple drivers trying to claim the same device, simply remove the entire IOMatchCategory key/value pair to use the default category, which is also what the standard macOS USB audio driver uses, and therefore only one driver will succeed at matching. Which one wins can be controlled via the different probe score levels for different USB matching patterns or, in unusual cases, using an explicit probe score.