Mac OS X video capture device hot plug driver support - macos

I'm developing driver for USB video capture device. First of all, I've started with CoreMediaIO sample:
https://developer.apple.com/library/content/samplecode/CoreMediaIO/Introduction/Intro.html
The kernel extension is based on IOVideoSample. It gets data from the USB device and sends to the assistant. Kext has IOKitPersonalities based on the USB device. So the device is real and should support HotPlug. Kext main class loads when the device is plugged in and unloads when the device is plugged out.
SampleAssistant was changed only to detect my kext class. PlugIn has NoCMIOHardwarePluginLazyLoadingInfo property.
When all video capture apps are closed - hotplug works well. Terminate function is being called from kext and kext object is being unloaded without any problem.
Even if you start video capture app with the stream from the device, then close it and plug out device - hotplug also works.
It works well with QuickTime player. It can find a stream and show an image, but there is one problem.
When QuickTime (or any other video capture app) works and show stream from the device - hotplug doesn't work. If you try to plug out the device it will remain in the system and USB port won't work until you reboot Mac. According to logs - terminate function wasn't called at all. Seems that something retains a link to the device.
I've started digging into the problem.
First of all, I figured out that SampleAssistant doesn't support hotplug by default. It has notification only for device arriving (DeviceArrived). I've added "interest" notification and handle only "kIOMessageSeviceIsTerminated" message - executing DeviceRemoved function and force deleting device object, but it didn't help.
There is also a file CMIO_DPA_Sample_Server_Stream.cpp. If you go to Stream::Start function and delete "mIOSAStream.Open;" and "mIOSAStream.Start();" lines - hotplug works.
Can you please advise what can be done to solve this problem?

Related

Microsoft SysVAD Virtual Audio Device Driver (SYSVAD) cannot work

This driver (https://github.com/Microsoft/Windows-driver-samples/tree/master/audio/sysvad) is provided by Microsoft. And in its README, the last part, it says:
Locate an MP3 or other audio file on the target computer and
double-click to play it. Then in the Sound dialog box, verify that
there is activity in the volume level indicator associated with the
SYSVAD (with APO Extensions) driver.
But in my target computer, the volume level indicator associated with the SYSVAD (with APO Extensions) driver does not change at all. And the target computer does not make any sound.
The same case to the mic, when set default mic to any of the sysvad mic array, the mic volume level will not change at all.
In my understanding, sysvad driver is virtual driver. So it will not really work. But why Microsoft README says: there is activity in the volume level indicator associated with the SYSVAD (with APO Extensions) driver.
The SYSVAD documentation leaves a lot to be desired. You won't see any activity in the volume level indicator, and you won't hear anything, since the only thing the rendering endpoints do is save a copy of the audio output to file (look for C:\STREAM_HOST_*.wav files).
The capture endpoints (including the "loopback" pins) generate constant sine-wave signals, which you can see if you use an app to record them, and then view them in a sound editor/viewer or play them back out to a real device.
I am working on SysVad too and sure it works, for Mic you can test with vlc player
Try to open the virtual mic from VLC and then you will hear sound, it's a sin wave generated by driver itself

Outputting Audio to the Built-In output device (Not the Default One)

I need to do some system-wide audio processing in my app.
I have installed Soundflower and selected it as my default output device in order to get the system audio. I know that Soundflower merely copies the mix buffer to a ThruBuffer and passes it to the apps so they can get it in their AudioDeviceIOProc callback.
What I don't understand is how to route the audio back to the Built-In output device after I've done the audio processing. I have the Soundflower device as the default, and it produces silence as I try to route the audio to the default output unit. Maybe what I need is to create a Multi-Output device in my program but I'm not sure how to do that.
You can create a multi-output device on osx - they're called "aggregate devices". You can do it manually in Audio MIDI Setup app and use that device in your app, or do it programmatically in your app.
If you do do it in app, example code seems to be rare. I cribbed the info I needed from this blog post.
NB the post is very old, I had to go to the Internet Archive Wayback Machine to find it.

Hide Audio device using codeless kext

I am developing a audio driver to do some custom audio processing using audio reflector driver sample code from Apple. Output from audio reflector driver is passed to real USB audio hardware device using core audio application. Now I want to hide USB audio hardware device from the system preferences so that user is not able to select the USB audio hardware output device as the default output device. Using the "SampleUSBAudioOverrideDriver" codeless kext I am able to change the name of output interface but not hide it. Any idea on how I will be able to hide USB audio hardware output device.
Thanks in advance.
Vin Pai
After a lof of R&D on this topic, I found that codeless kext provided in the sample code, SampleUSBAudioOverrideDriver doesn't use the property set to hide the device interface.

Hide USB Audio device on MAC OS X using custom kext

I am developing an application which does custom audio processing and sends the processed audio to the USB headset. My requirement is that the USB headset should not be visible to the user in the list of Audio output devices in System Preferences. Using "SampleUSBAudioOverrideDriver" code-less kext sample code from Apple, I'm able to change the interface name but I really need to hide it.
Is subclassing AppleUSBAudioDevice an option?
The recommended way to do pre-processing of a USB audio device's input and output streams in kernel space is to use the AppleUSBAudioPlugin API. This kext does not appear in the list of devices because it isn't an instance of IOAudioEngine, so there is no "hiding" involved.

Programmatically "unplug and replug" a USB device to load new driver in OS X?

I'm working on an installer in OS X that installs an IOKit driver for a USB device, and I'm trying to get it to not require a restart at the end. The installer installs the driver correctly and rebuilds the kext cache, and after it runs, if I unplug and replug the USB device, it correctly loads the new driver and everything works fine.
However, I don't want to require the user to physically unplug the device in order for the new driver to load. There's got to be a way to get OS X to load the new driver programmatically - in effect simulate the device being unplugged and plugged back in again, or something similar. How would I go about doing this? So far, hours of Googling has turned up nothing, so any help will be greatly appreciated!
IOUSBDeviceInterface187::USBDeviceReEnumerate() will do what you want. The only hitch is that to find all of the devices of interest and call this on them manually with IOServiceGetMatchingServices().
/*!
#function USBDeviceReEnumerate
#abstract Tells the IOUSBFamily to reenumerate the device.
#discussion This function will send a terminate message to all clients of the IOUSBDevice (such as
IOUSBInterfaces and their drivers, as well as the current User Client), emulating an unplug
of the device. The IOUSBFamily will then enumerate the device as if it had just
been plugged in. This call should be used by clients wishing to take advantage
of the Device Firmware Update Class specification. The device must be open to use this function.
#availability This function is only available with IOUSBDeviceInterface187 and above.
#param self Pointer to the IOUSBDeviceInterface.
#param options A UInt32 reserved for future use. Ignored in current implementation. Set to zero.
#result Returns kIOReturnSuccess if successful, kIOReturnNoDevice if there is no connection to an IOService,
or kIOReturnNotOpen if the device is not open for exclusive access.
*/
IOReturn (*USBDeviceReEnumerate)(void *self, UInt32 options);
Look in IOKit/usb/IOUSBLib.h
Take a look at diskutil, and especially the mount and unmount options. Those will softwarematically eject and mount devices. You can use diskutil list to get a list of all the currently mounted devices. If you need more info on diskutil, just look at the man page.

Resources