Skip to content

Commit 73d2c1c

Browse files
authored
Merge pull request #60 from jazzychad/jc-disambiguate-cameras
Disambiguate cameras with same product/vendor ids (issue #59)
2 parents 021ec45 + c2d9858 commit 73d2c1c

File tree

1 file changed

+64
-3
lines changed

1 file changed

+64
-3
lines changed

CameraController/UVC/Extensions/AVCaptureDevice+USB.swift

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,79 @@ private let kIOUSBInterfaceInterfaceID: CFUUID = CFUUIDGetConstantUUIDWithBytes
2929
typealias DeviceInterfacePointer = UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>>
3030

3131
extension AVCaptureDevice {
32-
func usbDevice() throws -> USBDevice {
32+
33+
private func getIOService() throws -> io_service_t {
34+
var camera: io_service_t = 0
3335
let cameraInformation = try self.modelID.extractCameraInformation()
3436
let dictionary: NSMutableDictionary = IOServiceMatching("IOUSBDevice") as NSMutableDictionary
3537
dictionary["idVendor"] = cameraInformation.vendorId
3638
dictionary["idProduct"] = cameraInformation.productId
3739

38-
var interfaceRef: UnsafeMutablePointer<UnsafeMutablePointer<IOUSBInterfaceInterface190>>?
39-
let camera: io_service_t = IOServiceGetMatchingService(kIOMasterPortDefault, dictionary)
40+
// adding other keys to this dictionary like kUSBProductString, kUSBVendorString, etc don't
41+
// seem to have any affect on using IOServiceGetMatchingService to get the correct camera,
42+
// so we instead get an iterator for the matching services based on idVendor and idProduct
43+
// and fetch their property dicts and then match against the more specific values
44+
45+
var iter: io_iterator_t = 0
46+
if IOServiceGetMatchingServices(kIOMasterPortDefault, dictionary, &iter) == kIOReturnSuccess {
47+
var cameraCandidate: io_service_t
48+
cameraCandidate = IOIteratorNext(iter)
49+
while cameraCandidate != 0 {
50+
var propsRef: Unmanaged<CFMutableDictionary>?
51+
52+
if IORegistryEntryCreateCFProperties(
53+
cameraCandidate,
54+
&propsRef,
55+
kCFAllocatorDefault,
56+
0) == kIOReturnSuccess {
57+
if let properties = propsRef?.takeRetainedValue() {
58+
59+
// these are common keys that might have the device name stored in the propery dictionary
60+
let keysToTry: [String] = [
61+
"kUSBProductString",
62+
"kUSBVendorString",
63+
"USB Product Name",
64+
"USB Vendor Name"
65+
]
66+
67+
var found: Bool = false
68+
for key in keysToTry {
69+
if let cameraName = (properties as NSDictionary)[key] as? String {
70+
if cameraName == self.localizedName {
71+
// we have a match, use this as the camera
72+
camera = cameraCandidate
73+
found = true
74+
// break out of `for key in keysToTry`
75+
break
76+
}
77+
}
78+
}
79+
if found {
80+
// break out of `while (cameraCandidate != 0)`
81+
break
82+
}
83+
}
84+
}
85+
cameraCandidate = IOIteratorNext(iter)
86+
}
87+
}
88+
89+
// if we haven't found a camera after looping through the iterator, fallback on GetMatchingService method
90+
if camera == 0 {
91+
camera = IOServiceGetMatchingService(kIOMasterPortDefault, dictionary)
92+
}
93+
94+
return camera
95+
}
96+
97+
func usbDevice() throws -> USBDevice {
98+
99+
let camera = try self.getIOService()
40100
defer {
41101
let code: kern_return_t = IOObjectRelease(camera)
42102
assert( code == kIOReturnSuccess )
43103
}
104+
var interfaceRef: UnsafeMutablePointer<UnsafeMutablePointer<IOUSBInterfaceInterface190>>?
44105
var configDesc: IOUSBConfigurationDescriptorPtr?
45106
try camera.ioCreatePluginInterfaceFor(service: kIOUSBDeviceUserClientTypeID) {
46107
let deviceInterface: DeviceInterfacePointer = try $0.getInterface(uuid: kIOUSBDeviceInterfaceID)

0 commit comments

Comments
 (0)