Reputation: 1362
If I have an AVCaptureDevice, how can I get the related USB interface so I can access the underlying hardware via IOKit?
I've tried finding it via vid & pid, but this won't work if I plug in two devices with the same vid, pid. Here's the code I use to extract vid and pid from AVCaptureDevice:
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithDeviceType:AVMediaTypeVideo];
NSString *modelID = [device modelID];
NSRange vidRange = [modelID rangeOfString:@"VendorID_"];
int vid = [[modelID substringWithRange:NSMakeRange(vidRange.location + 9, 5)] intValue];
NSRange pidRange = [modelID rangeOfString:@"ProductID_"];
int vid = [[modelID substringWithRange:NSMakeRange(pidRange.location + 10, 5)] intValue];
And then I search for a matching IOService:
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
CFNumberRef numberRef;
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vid);
CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
CFRelease(numberRef);
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pid);
CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef);
CFRelease(numberRef);
io_service_t camera = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
Upvotes: 2
Views: 1175
Reputation: 391
In the case of video devices, the AVCaptureDevice uniqueID seems to a string in the form "0xLLLLLLLLVVVVPPPP", where:
e.g. 0x144000002E1A4C01
(This not documented anywhere by Apple; what I'm saying above is completely by inference, which is why I say "seems to be".)
These three values should correspond to the values returned when interrogating an io_service_t
CFNumberRef vendorIdObj = IORegistryEntrySearchCFProperty(ioService, kIOUSBPlane, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0);
CFNumberRef productIdObj = IORegistryEntrySearchCFProperty(ioService, kIOUSBPlane, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
CFNumberRef locationIdObj = IORegistryEntrySearchCFProperty(ioService, kIOUSBPlane, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
By decoding the uniqueID string into its three components, you should be able to then compare them to the values returned by the IORegistryEntrySearchCFProperty functions above, allowing you to get the USB Interface for the AVCaptureDevice.
Upvotes: 0
Reputation: 36072
Maybe a combination of AVCaptureDevice
modelID
and uniqueID
could help you find the matching IOService
. The formatting of the two IDs looks to be both undocumented and dependent on transport and media-type, but you should be able to figure something out. Here is a tentative mapping for USB audio (because I don't have any USB cameras), based on two devices:
modelID: USB Headphone Set:0C76:1607
uniqueID: AppleUSBAudioEngine:Unknown Manufacturer:USB Headphone Set:14200000:2,1,
USB Headphone Set:
Product ID: 0x1607
Vendor ID: 0x0c76 (Solid State System Co., Ltd.)
Version: 1.00
Speed: Up to 12 Mb/sec
Location ID: 0x14200000 / 9
Current Available (mA): 1000
Current Required (mA): 100
Extra Operating Current (mA): 0
uniqueID: AppleUSBAudioEngine:Burr-Brown from TI :USB Audio CODEC :14200000:2,
modelID: USB Audio CODEC :08BB:2902
USB Audio CODEC :
Product ID: 0x2902
Vendor ID: 0x08bb (Texas Instruments Japan)
Version: 1.00
Speed: Up to 12 Mb/sec
Manufacturer: Burr-Brown from TI
Location ID: 0x14200000 / 10
Current Available (mA): 1000
Current Required (mA): 100
Extra Operating Current (mA): 0
The (usb audio) format is something like
modelID: name:vendorID:productID
uniqueID: AppleUSBAudioEngine:Manufacturer or Unknown Manufacturer:location ID:???
If USB video's uniqueID
is similar, then the combination of productID
, vendorID
and locationID
(which USB port) should be enough to uniquely identify the underlying device's hardware, albeit in a fragile and undocumented way.
Upvotes: 1