@@ -29,18 +29,79 @@ private let kIOUSBInterfaceInterfaceID: CFUUID = CFUUIDGetConstantUUIDWithBytes
2929typealias DeviceInterfacePointer = UnsafeMutablePointer < UnsafeMutablePointer < IOUSBDeviceInterface > >
3030
3131extension 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