hid_enumerate specify multiple VID/PID combos. #225

Open
opened 2020-12-24 07:52:50 -06:00 by FabianKopp · 12 comments
FabianKopp commented 2020-12-24 07:52:50 -06:00 (Migrated from github.com)

As of now you can only specify one pair of VID PID in the hid_enumerate function. Is it possible to have a version where you can supply multiple sets of VID PIDs to the function? This would be of great use for anyone scanning for multiple products.

As of now you can only specify one pair of VID PID in the hid_enumerate function. Is it possible to have a version where you can supply multiple sets of VID PIDs to the function? This would be of great use for anyone scanning for multiple products.
Youw commented 2020-12-25 05:45:01 -06:00 (Migrated from github.com)

use hid_enumerate with (0, 0) VID/PID - it will give you all the devices, so you can filter that list on your own.

use `hid_enumerate` with `(0, 0)` VID/PID - it will give you all the devices, so you can filter that list on your own.
FabianKopp commented 2020-12-25 06:02:46 -06:00 (Migrated from github.com)

Right, but it turns out that running hid_enumerate(0,0) repeatedly is very bad and causes many issues on user's computers. For example it can cause clicking sounds on microphones and make other HID devices unusable. It is better to filter within the enumerate function than to run a full getDescriptor request on every single hid device on the computer.

Right, but it turns out that running hid_enumerate(0,0) repeatedly is very bad and causes many issues on user's computers. For example it can cause clicking sounds on microphones and make other HID devices unusable. It is better to filter within the enumerate function than to run a full getDescriptor request on every single hid device on the computer.
Youw commented 2020-12-25 06:04:37 -06:00 (Migrated from github.com)

Not repeatedly. Enumerate once - search/filter all the devices you need in that list.

Not repeatedly. Enumerate once - search/filter all the devices you need in that list.
FabianKopp commented 2020-12-25 06:06:12 -06:00 (Migrated from github.com)

But if you have a program and device where you have to repeatedly check for when the device was inserted or removed on the fly this does not work.

But if you have a program and device where you have to repeatedly check for when the device was inserted or removed on the fly this does not work.
Youw commented 2020-12-25 06:11:17 -06:00 (Migrated from github.com)

I'm confused. Checking for hotplug/unplug events is entirely different problem, then you originally described (finding multiple devices with a single hid_enumerate).

I'm confused. Checking for hotplug/unplug events is entirely different problem, then you originally described (finding multiple devices with a single `hid_enumerate`).
FabianKopp commented 2020-12-25 06:33:11 -06:00 (Migrated from github.com)

One detects plug and unplug events by repeatedly enumerating the the devices and checking the difference between enumerations

One detects plug and unplug events by repeatedly enumerating the the devices and checking the difference between enumerations
Youw commented 2020-12-25 07:33:15 -06:00 (Migrated from github.com)

And how passing multiple VIDs/PIDs into hid_enumerate help with "audio clicks" each time you call it?

And how passing multiple VIDs/PIDs into hid_enumerate help with "audio clicks" each time you call it?
FabianKopp commented 2020-12-25 07:51:22 -06:00 (Migrated from github.com)

When you do hid_enumerate(0,0) it executes getDescriptor requests on every single usb device on your computer even devices such as microphones that I'm not interested in. Resource limited devices with weak CPUs such a microphones cannot do their regular job and respond to the request at the same time. When the microphone receives the request it stops streaming audio data briefly so that it can respond. This can be heard as a short "pop" or "click". If we call hid_enumerate without wildcards and only specify which devices we care about, it avoids sending this disruptive getDescriptor request to sensitive devices such as microphones, etc.

When you do hid_enumerate(0,0) it executes getDescriptor requests on every single usb device on your computer even devices such as microphones that I'm not interested in. Resource limited devices with weak CPUs such a microphones cannot do their regular job and respond to the request at the same time. When the microphone receives the request it stops streaming audio data briefly so that it can respond. This can be heard as a short "pop" or "click". If we call hid_enumerate without wildcards and only specify which devices we care about, it avoids sending this disruptive getDescriptor request to sensitive devices such as microphones, etc.
todbot commented 2020-12-25 14:36:55 -06:00 (Migrated from github.com)

In general, I would advise against using hid_enumerate() to detect insertion/removal events because it's so taxing to the USB bus system.

Instead, use an OS-specific USB insertion/removal event system. I don't know of a hidapi-like cross-platform C-based API for doing this, but you can check out the Nodejs package node-usb-detection to see the platform-specific code they use for Windows (RegisterDeviceNotificationA()), MacOS (IONotificationPortCreate()), and Linux (udev_monitor_receive_device()): https://github.com/MadLittleMods/node-usb-detection/tree/master/src

Another thing to note, there is a delay between device inserted and when it's available to hidapi, as the OS has to hook in the USB and HID driver. I've seen this delay be up to several seconds on MacOS and Windows.

In general, I would advise against using `hid_enumerate()` to detect insertion/removal events because it's so taxing to the USB bus system. Instead, use an OS-specific USB insertion/removal event system. I don't know of a hidapi-like cross-platform C-based API for doing this, but you can check out the Nodejs package `node-usb-detection` to see the platform-specific code they use for Windows (`RegisterDeviceNotificationA()`), MacOS (`IONotificationPortCreate()`), and Linux (`udev_monitor_receive_device()`): https://github.com/MadLittleMods/node-usb-detection/tree/master/src Another thing to note, there is a delay between device inserted and when it's available to `hidapi`, as the OS has to hook in the USB and HID driver. I've seen this delay be up to several seconds on MacOS and Windows.
Youw commented 2020-12-25 15:26:11 -06:00 (Migrated from github.com)

Very good point from Tod.

Thanks for the explanation @FabianKopp, I think I understand your problem now.

it executes getDescriptor requests on every single usb device

  1. So I presume, it is not called when you enumerate the devices with a specific PID/VID?
  2. There is no direct call to what you call a getDescriptor in windows implementation, after the device is enumerated. All I see is HidD_GetPreparsedData, HidP_GetCaps and HidD_Get***String calls. Can you track down which one of those actually causing the negative "clicks" effect you mentioned?
Very good point from Tod. Thanks for the explanation @FabianKopp, I think I understand your problem now. > it executes getDescriptor requests on every single usb device 1) So I presume, it is not called when you enumerate the devices with a specific PID/VID? 2) There is no direct call to what you call a `getDescriptor` in [windows implementation](https://github.com/libusb/hidapi/blob/master/windows/hid.c), after the device is enumerated. All I see is `HidD_GetPreparsedData`, `HidP_GetCaps` and `HidD_Get***String` calls. Can you track down which one of those actually causing the negative "clicks" effect you mentioned?
FabianKopp commented 2020-12-25 17:00:24 -06:00 (Migrated from github.com)

Its pretty much everything after this filtering line: if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) && (product_id == 0x0 || attrib.ProductID == product_id)) { Its HidD_GetPreparsedData, HidP_GetCaps, HidD_GetSerialNumberString, HidD_GetManufacturerString, HidD_GetProductString. These calls are taxing to the usb device and can be avoided on other devices by specifying the vid/pid you are looking for and ignoring the rest. I just think it would really helpful to be able to specify multiple vid/pids in case you are looking for 2 or more types of devices.

Its pretty much everything after this filtering line: `if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) && (product_id == 0x0 || attrib.ProductID == product_id)) {` Its `HidD_GetPreparsedData`, `HidP_GetCaps`, `HidD_GetSerialNumberString`, `HidD_GetManufacturerString`, `HidD_GetProductString`. These calls are taxing to the usb device and can be avoided on other devices by specifying the vid/pid you are looking for and ignoring the rest. I just think it would really helpful to be able to specify multiple vid/pids in case you are looking for 2 or more types of devices.
Youw commented 2020-12-26 02:47:22 -06:00 (Migrated from github.com)

I'm asking, because I was thinking a more general aproach: enumerate function, that accepts a filter function over devices attrigutes (or even over a hid_device_info), but I guess it wouldn't help your case, since only VID/PID is available for filtering, without causing negative effect on your audio device(s).

I'm asking, because I was thinking a more general aproach: enumerate function, that accepts a filter function over devices attrigutes (or even over a hid_device_info), but I guess it wouldn't help your case, since only VID/PID is available for filtering, without causing negative effect on your audio device(s).
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-libusb/hidapi#225
No description provided.