OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/device_monitor_mac.h" | |
6 | |
7 #include <IOKit/usb/IOUSBLib.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/mac/scoped_cftyperef.h" | |
11 #include "base/mac/scoped_ioobject.h" | |
12 | |
13 namespace content { | |
14 | |
15 namespace { | |
16 | |
17 struct { | |
no longer working on chromium
2012/08/08 09:23:16
We can't use const struct here because we need to
Mark Mentovai
2012/08/08 12:38:03
That’s exactly the problem I was illustrating. It
| |
18 base::SystemMonitor::DeviceType device_type; | |
19 const io_name_t service_type; | |
20 } kDeviceServices[] = { | |
21 // Add new services here if needed. | |
22 { base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kIOMatchedNotification }, | |
23 { base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kIOTerminatedNotification }, | |
24 { base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kIOMatchedNotification }, | |
25 { base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kIOTerminatedNotification }, | |
26 }; | |
27 | |
28 CFMutableDictionaryRef CreateMatchingDictionary( | |
29 SInt32 interface_class_code, SInt32 interface_subclass_code) { | |
30 CFMutableDictionaryRef matching_dictionary = IOServiceMatching( | |
31 kIOUSBInterfaceClassName); | |
32 base::mac::ScopedCFTypeRef<CFNumberRef> number_ref(CFNumberCreate( | |
33 kCFAllocatorDefault, kCFNumberSInt32Type, &interface_class_code)); | |
34 DCHECK(number_ref); | |
35 CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBInterfaceClass), | |
36 number_ref); | |
37 | |
38 number_ref.reset(CFNumberCreate(kCFAllocatorDefault, | |
39 kCFNumberSInt32Type, | |
40 &interface_subclass_code)); | |
41 DCHECK(number_ref); | |
42 CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBInterfaceSubClass), | |
43 number_ref); | |
44 | |
45 return matching_dictionary; | |
46 } | |
47 | |
48 void AddCallbackToIOService(IONotificationPortRef port, | |
49 const io_name_t type, | |
50 CFMutableDictionaryRef dictionary, | |
51 IOServiceMatchingCallback callback, | |
52 void* context, | |
53 io_iterator_t* notification) { | |
54 kern_return_t err = IOServiceAddMatchingNotification(port, | |
55 type, | |
56 dictionary, | |
57 callback, | |
58 context, | |
59 notification); | |
60 if (err) { | |
61 NOTREACHED() << "Failed to register the IO matched notification for type " | |
62 << type; | |
63 return; | |
64 } | |
65 DCHECK(*notification); | |
66 | |
67 // Iterate over set of matching devices to access already-present devices | |
68 // and to arm the notification. | |
69 base::mac::ScopedIOObject<io_service_t> this_object( | |
70 IOIteratorNext(*notification)); | |
71 for (; this_object; this_object.reset(IOIteratorNext(*notification))); | |
72 } | |
73 | |
74 } // namespace | |
75 | |
76 DeviceMonitorMac::DeviceMonitorMac() { | |
77 | |
78 // Add the notification port to the run loop. | |
79 notification_port_ = IONotificationPortCreate(kIOMasterPortDefault); | |
80 DCHECK(notification_port_); | |
81 | |
82 RegisterServices(); | |
83 | |
84 CFRunLoopAddSource(CFRunLoopGetCurrent(), | |
85 IONotificationPortGetRunLoopSource(notification_port_), | |
86 kCFRunLoopCommonModes); | |
87 } | |
88 | |
89 DeviceMonitorMac::~DeviceMonitorMac() { | |
90 // Stop the notifications and free the objects. | |
91 for (size_t i = 0; i < arraysize(kDeviceServices); ++i) { | |
92 IOObjectRelease(notification_iterators_[i]); | |
93 } | |
94 | |
95 // Remove the sleep notification port from the application runloop. | |
96 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), | |
97 IONotificationPortGetRunLoopSource(notification_port_), | |
98 kCFRunLoopCommonModes); | |
99 | |
100 // Destroy the notification port allocated by IONotificationPortCreate. | |
101 IONotificationPortDestroy(notification_port_); | |
102 } | |
103 | |
104 void DeviceMonitorMac::RegisterServices() { | |
105 notification_iterators_.reset(new io_iterator_t[arraysize(kDeviceServices)]); | |
106 CFMutableDictionaryRef matching_dictionary; | |
107 for (size_t i = 0; i < arraysize(kDeviceServices); ++i) { | |
108 switch (kDeviceServices[i].device_type) { | |
109 case base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE: | |
110 matching_dictionary = CreateMatchingDictionary( | |
111 kUSBAudioInterfaceClass, kUSBAudioControlSubClass); | |
112 break; | |
113 case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: | |
114 matching_dictionary = CreateMatchingDictionary( | |
115 kUSBVideoInterfaceClass, kUSBVideoControlSubClass); | |
116 break; | |
117 default: | |
118 NOTREACHED(); | |
119 return; | |
120 } | |
121 | |
122 // Add callback to the service. | |
123 AddCallbackToIOService(notification_port_, | |
124 kDeviceServices[i].service_type, | |
125 matching_dictionary, | |
126 &DeviceChangedCallback, | |
127 static_cast<void*>(&kDeviceServices[i].device_type), | |
128 ¬ification_iterators_[i]); | |
129 } | |
130 } | |
131 | |
132 void DeviceMonitorMac::DeviceChangedCallback(void *context, | |
133 io_iterator_t iterator) { | |
134 base::mac::ScopedIOObject<io_service_t> this_object(IOIteratorNext(iterator)); | |
135 for (; this_object; this_object.reset(IOIteratorNext(iterator))) { | |
136 if (context) { | |
137 base::SystemMonitor::DeviceType device_type = | |
138 *reinterpret_cast<base::SystemMonitor::DeviceType*>(context); | |
139 DCHECK(device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE || | |
140 device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); | |
141 // TODO(xians): Remove the global variable for SystemMonitor. | |
142 base::SystemMonitor::Get()->ProcessDevicesChanged(device_type); | |
143 } | |
144 } | |
145 } | |
146 | |
147 } // namespace content | |
OLD | NEW |