Index: content/browser/device_monitor_mac.cc |
diff --git a/content/browser/device_monitor_mac.cc b/content/browser/device_monitor_mac.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0bc69a96029c04f715d5d5f55ab30dcb774f92ee |
--- /dev/null |
+++ b/content/browser/device_monitor_mac.cc |
@@ -0,0 +1,147 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// 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 { |
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
|
+ base::SystemMonitor::DeviceType device_type; |
+ const io_name_t service_type; |
+} 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, |
+ 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))); |
+} |
+ |
+} // namespace |
+ |
+DeviceMonitorMac::DeviceMonitorMac() { |
+ |
+ // Add the notification port to the run loop. |
+ notification_port_ = IONotificationPortCreate(kIOMasterPortDefault); |
+ DCHECK(notification_port_); |
+ |
+ RegisterServices(); |
+ |
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), |
+ IONotificationPortGetRunLoopSource(notification_port_), |
+ kCFRunLoopCommonModes); |
+} |
+ |
+DeviceMonitorMac::~DeviceMonitorMac() { |
+ // Stop the notifications and free the objects. |
+ for (size_t i = 0; i < arraysize(kDeviceServices); ++i) { |
+ IOObjectRelease(notification_iterators_[i]); |
+ } |
+ |
+ // 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) { |
+ 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))) { |
+ 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 |