-
-
Notifications
You must be signed in to change notification settings - Fork 57
API function to get macOS LocationID and Windows ContainerID of an USB device #107
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
Comments
Do you have some sample code of how to do this ? |
For macOS you need to get the For Windows you need to get the |
Thanks. Now I have to find how I get these device nodes in MS Windows, as right now the code does not use these APIs AFAIK. |
I'm revisiting this and am wondering: port_information already stores the MIDIObjectRef's UUID so you can get it back in the following way (typing this without access to macOS so likely there are some mistakes but you get the gist): int32_t usb_id_from_port(const libremidi::port_information& info) {
// Get the MIDI object from the uid
auto uid = std::bit_cast<std::int32_t>((uint32_t)info.port);
MIDIObjectRef object{};
MIDIObjectType type{};
auto ret = MIDIObjectFindByUniqueID(uid, &object, &type);
assert(type == kMIDIObjectType_Source || type == kMIDIObjectType_Destination);
// Get the MIDI entity from the object
MIDIEntityRef entity{};
MIDIEndpointGetEntity(object, &entity);
if(!entity)
throw; // It means it's not a hardware port
// Get the MIDI device from the entity
MIDIDeviceRef device{};
MIDIEntityGetDevice(entity, &device);
if(!device)
throw;
SInt32 res{};
MIDIObjectGetIntegerProperty(device, CFSTR("USBDeviceID"), &res);
return res;
} For Windows I investigated but I see absolutely no way to get the device ID from the WinMM API. :/ |
What about this approach: #include <windows.h>
#include <setupapi.h>
#include <devpkey.h>
#include <iostream>
#include <string>
#include <initguid.h>
#pragma comment(lib, "setupapi.lib")
void CheckMidiDevices() {
// Get the device information set for all MIDI devices
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(NULL, "SWD\\MMDEVAPI\\{0.0.1.00000000}.{00000000-0000-0000-0000-000000000000}", NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to get device information set." << std::endl;
return;
}
SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// Enumerate through all devices in the set
for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoSet, i, &deviceInfoData); ++i) {
// Get the device instance ID
char deviceInstanceId[MAX_DEVICE_ID_LEN];
if (CM_Get_Device_ID(deviceInfoData.DevInst, deviceInstanceId, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) {
continue;
}
// Get the device description
char deviceDescription[256];
if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)deviceDescription, sizeof(deviceDescription), NULL)) {
std::cout << "Device: " << deviceDescription << std::endl;
}
// Get the ContainerID
DEVPROPTYPE propType;
GUID containerId;
if (SetupDiGetDeviceProperty(deviceInfoSet, &deviceInfoData, &DEVPKEY_Device_ContainerId, &propType, (PBYTE)&containerId, sizeof(containerId), NULL, 0)) {
LPOLESTR guidString;
StringFromCLSID(containerId, &guidString);
std::wcout << L"ContainerID: " << guidString << std::endl;
CoTaskMemFree(guidString);
}
// Get the device's parent to determine the connection type
DEVINST parentDevInst;
if (CM_Get_Parent(&parentDevInst, deviceInfoData.DevInst, 0) == CR_SUCCESS) {
char parentDeviceInstanceId[MAX_DEVICE_ID_LEN];
if (CM_Get_Device_ID(parentDevInst, parentDeviceInstanceId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS) {
// Check if the parent device is a USB or Bluetooth device
if (strstr(parentDeviceInstanceId, "USB") != NULL) {
std::cout << "Connection Type: USB" << std::endl;
} else if (strstr(parentDeviceInstanceId, "BTH") != NULL) {
std::cout << "Connection Type: Bluetooth" << std::endl;
} else {
std::cout << "Connection Type: Other" << std::endl;
}
}
}
}
// Clean up
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
int main() {
CheckMidiDevices();
return 0;
} |
hm but do we know for sure that the index of
is the same index than the one used by WinMM to enumerate MIDI devices ? |
especially in "borderline" cases where we plug multiple identical MIDI devices which have historically been iffy in winmm |
I don't know unfortunately. |
hmm so I've been trying to add the windows code you sent but here it doesn't work:
gives me the same error than here: https://stackoverflow.com/questions/14288626/obtain-device-information-set-for-monitors-returned-handle-is-always-invalid-ha I tried to be more general and ask for every MMDEVAPI device:
but the reported devices don't match the ones I get from
but for instance this does not list my RME Multiface II's MIDI inputs.
and the ports in the order reported by winmm:
Do you have any idea ? |
the good thing though is that the more recent Windows MIDI API, Windows MIDI Services, directly gives access to the container ID, so I'll be adding it to the API anyways |
done in HEAD :) here's the API, the info will just be provided by default as part of port_information: |
I also added an enum that gives some info about what kind of port this is (hardware, software etc) |
Great! Thank you very much for implementing this! This provides us on the MIDI side with the basis for hotplugging complex USB devices using multiple USB protocol classes on different interfaces. |
yep, all the infrastructure is there to add it to any backend :) |
just added the implementation for ALSA based on what useful information I could gather from udev (although the ALSA card was already accessible in a way):
|
I don't think that "pci-0000:00:14.0-usb-0:12:1.0" is compareable in functionality to ContainerID or LocationID. The later are containers that group everything that belongs to a device, independent of the physical interface. Especially relevant in case of devices with multiple physical interfaces for the same functionality, e.g. a printer with LAN, WLAN and USB will have one single ContainerID or LocationID and this stays the same when switching from WLAN to USB. And if you have two of these printers connected, you will be able to distinguish by ContainerID or LocationID, even if they have excatly the same type. |
hmm I see. I think none of the devices I have support this to try and see what's useful :/ do you know of some MIDI-related device that exhibits this functionality ? From the MSDN docs: "The manufacturer of the USB device specifies the ContainerID in the device's firmware by using a Microsoft OS ContainerID descriptor. |
Also it seems to be pretty different from macOS's location ID, which is not related to the device but changes every time the device is unplugged / replugged |
I don't have such a device, but I'm thinking about MIDI devices like the Hercules Universal DJ ( https://support.hercules.com/en/product/universaldj-en/ ) which can use MIDI over USB and MIDI over Bluetooth at the same time. |
For compound USB devices, that have not only a MIDI interface, but interfaces used with other USB device classes (e.g. a display) as well, it is needed to group them. The operating systems macOS and Windows provide identifiers for this purpose:
It would be nice, if the libremidi API would provide getters, to get these IDs for an USB device.
The text was updated successfully, but these errors were encountered: