Index: content/browser/device_monitor_mac.mm |
diff --git a/content/browser/device_monitor_mac.mm b/content/browser/device_monitor_mac.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e5d40d52c82ee8f9fb5e6c771e595884dc894e66 |
--- /dev/null |
+++ b/content/browser/device_monitor_mac.mm |
@@ -0,0 +1,148 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
Mark Mentovai
2012/08/07 18:39:10
Why is this a .mm file? You haven’t used any Objec
no longer working on chromium
2012/08/08 08:42:42
It is a following design from gamepad/platform_dat
|
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/device_monitor_mac.h" |
+ |
+#include <IOKit/usb/IOUSBLib.h> |
+ |
+#include "base/logging.h" |
+#include "base/mac/scoped_cftyperef.h" |
+#include "base/mac/scoped_ioobject.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+struct { |
Mark Mentovai
2012/08/07 18:39:10
const?
no longer working on chromium
2012/08/08 08:42:42
Done.
|
+ base::SystemMonitor::DeviceType device_type; |
+ const io_name_t service_type; |
Mark Mentovai
2012/08/07 18:39:10
…but this doesn’t really need to be const
no longer working on chromium
2012/08/08 08:42:42
I think it is a c_string, isn't it better to put i
|
+} kDeviceServices[] = { |
+ // Add new services here if needed. |
+ { base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kIOMatchedNotification }, |
+ { base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kIOTerminatedNotification }, |
+ { base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kIOMatchedNotification }, |
+ { base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kIOTerminatedNotification }, |
+}; |
+ |
+CFMutableDictionaryRef CreateMatchingDictionary( |
+ SInt32 interface_class_code, SInt32 interface_subclass_code) { |
+ CFMutableDictionaryRef matching_dictionary = IOServiceMatching( |
+ kIOUSBInterfaceClassName); |
+ base::mac::ScopedCFTypeRef<CFNumberRef> number_ref(CFNumberCreate( |
+ kCFAllocatorDefault, kCFNumberSInt32Type, &interface_class_code)); |
+ DCHECK(number_ref); |
+ CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBInterfaceClass), |
+ number_ref); |
+ |
+ number_ref.reset(CFNumberCreate(kCFAllocatorDefault, |
+ kCFNumberSInt32Type, |
+ &interface_subclass_code)); |
+ DCHECK(number_ref); |
+ CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBInterfaceSubClass), |
+ number_ref); |
+ |
+ return matching_dictionary; |
+} |
+ |
+void AddCallbackToIOService(IONotificationPortRef port, |
+ const io_name_t type, |
+ CFMutableDictionaryRef dictionary, |
+ IOServiceMatchingCallback callback, |
+ void* context, |
+ io_iterator_t* notification) { |
+ kern_return_t err = IOServiceAddMatchingNotification(port, |
Mark Mentovai
2012/08/07 18:39:10
Weird indentation.
no longer working on chromium
2012/08/08 08:42:42
thanks.
|
+ type, |
+ dictionary, |
+ callback, |
+ context, |
+ notification); |
+ if (err) { |
+ NOTREACHED() << "Failed to register the IO matched notification for type " |
+ << type; |
+ return; |
+ } |
+ DCHECK(*notification); |
+ |
+ // Iterate over set of matching devices to access already-present devices |
+ // and to arm the notification. |
+ base::mac::ScopedIOObject<io_service_t> this_object( |
+ IOIteratorNext(*notification)); |
+ for (; this_object; this_object.reset(IOIteratorNext(*notification))); |
Mark Mentovai
2012/08/07 18:39:10
Use {} to show an empty body. Also see the comment
no longer working on chromium
2012/08/08 08:42:42
Done.
I replied the comment at line 136.
|
+} |
+ |
+} // namespace |
+ |
+DeviceMonitorMac::DeviceMonitorMac() { |
+ CFRunLoopRef runloop = CFRunLoopGetCurrent(); |
Mark Mentovai
2012/08/07 18:39:10
You can save doing this until you’re ready to add
no longer working on chromium
2012/08/08 08:42:42
Done.
|
+ |
+ // Add the notification port to the run loop. |
+ notification_port_ = IONotificationPortCreate(kIOMasterPortDefault); |
+ DCHECK(notification_port_); |
+ CFRunLoopSourceRef notification_cfsource = |
+ IONotificationPortGetRunLoopSource(notification_port_); |
+ |
+ RegisterServices(); |
+ |
+ CFRunLoopAddSource(runloop, notification_cfsource, kCFRunLoopCommonModes); |
+} |
+ |
+DeviceMonitorMac::~DeviceMonitorMac() { |
+ // Stop the notifications and free the objects. |
+ for (size_t i = 0; i < arraysize(kDeviceServices); ++i) { |
Mark Mentovai
2012/08/07 18:39:10
This looks a little freaky. Why don’t you use a st
no longer working on chromium
2012/08/08 08:42:42
a scoped_array is much more suitable here because
Mark Mentovai
2012/08/08 12:32:57
Aside from the ability to resize a std::vector (wh
|
+ IOObjectRelease(notification_iterators_[i]); |
Avi (use Gerrit)
2012/08/06 20:29:47
Aha, cool.
|
+ } |
+ |
+ // Remove the sleep notification port from the application runloop. |
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), |
+ IONotificationPortGetRunLoopSource(notification_port_), |
+ kCFRunLoopCommonModes); |
+ |
+ // Destroy the notification port allocated by IONotificationPortCreate. |
+ IONotificationPortDestroy(notification_port_); |
+} |
+ |
+void DeviceMonitorMac::RegisterServices() { |
+ notification_iterators_.reset(new io_iterator_t[arraysize(kDeviceServices)]); |
+ CFMutableDictionaryRef matching_dictionary; |
+ for (size_t i = 0; i < arraysize(kDeviceServices); ++i) { |
+ switch (kDeviceServices[i].device_type) { |
wjia(left Chromium)
2012/08/07 20:57:27
After chatting with mmentovai@, my understanding i
no longer working on chromium
2012/08/08 08:42:42
NO.
I thought I had already explained clearly abou
|
+ case base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE: |
+ matching_dictionary = CreateMatchingDictionary( |
+ kUSBAudioInterfaceClass, kUSBAudioControlSubClass); |
+ break; |
+ case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: |
+ matching_dictionary = CreateMatchingDictionary( |
+ kUSBVideoInterfaceClass, kUSBVideoControlSubClass); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ // Add callback to the service. |
+ AddCallbackToIOService(notification_port_, |
+ kDeviceServices[i].service_type, |
+ matching_dictionary, |
+ &DeviceChangedCallback, |
+ static_cast<void*>(&kDeviceServices[i].device_type), |
+ ¬ification_iterators_[i]); |
+ } |
+} |
+ |
+void DeviceMonitorMac::DeviceChangedCallback(void *context, |
+ io_iterator_t iterator) { |
+ base::mac::ScopedIOObject<io_service_t> this_object(IOIteratorNext(iterator)); |
+ for (; this_object; this_object.reset(IOIteratorNext(iterator))) { |
Mark Mentovai
2012/08/07 18:39:10
I’d write the initialization inside the body of th
no longer working on chromium
2012/08/08 08:42:42
:) I think I have got different opinions on this s
Mark Mentovai
2012/08/08 12:32:57
Whoever’s opinion you got in the past on this was
|
+ if (context) { |
+ base::SystemMonitor::DeviceType device_type = |
+ *reinterpret_cast<base::SystemMonitor::DeviceType*>(context); |
+ DCHECK(device_type == base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE || |
+ device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
+ // TODO(xians): Remove the global variable for SystemMonitor. |
+ base::SystemMonitor::Get()->ProcessDevicesChanged(device_type); |
+ } |
+ } |
+} |
+ |
+} // namespace content |