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..07ecf4751ee4e609f286590db5a5517763f5c251 |
--- /dev/null |
+++ b/content/browser/device_monitor_mac.mm |
@@ -0,0 +1,165 @@ |
+// 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 <CoreFoundation/CFNumber.h> |
+#include <CoreFoundation/CoreFoundation.h> |
+#include <IOKit/usb/IOUSBLib.h> |
+ |
+#include "base/logging.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+DeviceMonitorMac* InstanceFromContext(void* context) { |
Avi (use Gerrit)
2012/08/03 19:41:23
Does this help in readability? I'd think folding i
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ return reinterpret_cast<DeviceMonitorMac*>(context); |
+} |
+ |
+void AddValueToDictionary(CFMutableDictionaryRef dictionary, |
Avi (use Gerrit)
2012/08/03 19:41:23
Ditto. If you use scoped_cftyperef, this collapses
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ SInt32 code, |
+ const void *key) { |
+ CFNumberRef number_ref = CFNumberCreate(kCFAllocatorDefault, |
Avi (use Gerrit)
2012/08/03 19:41:23
scoped_cftyperef.
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ kCFNumberSInt32Type, |
+ &code); |
+ if (!number_ref) { |
+ NOTREACHED() << "failed to create CFNumberRef for " << code; |
+ return; |
+ } |
+ |
+ CFDictionaryAddValue(dictionary, key, number_ref); |
+ CFRelease(number_ref); |
+} |
+ |
+CFMutableDictionaryRef CreateMachingDictionary(SInt32 interface_class_code, |
Avi (use Gerrit)
2012/08/03 19:41:23
s/CreateMachingDictionary/CreateMatchingDictionary
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ SInt32 interface_subclass_code) { |
+ CFMutableDictionaryRef matching_dictionary = IOServiceMatching( |
+ kIOUSBInterfaceClassName); |
+ AddValueToDictionary(matching_dictionary, interface_class_code, |
+ CFSTR(kUSBInterfaceClass)); |
+ AddValueToDictionary(matching_dictionary, interface_subclass_code, |
+ CFSTR(kUSBInterfaceSubClass)); |
+ |
+ return matching_dictionary; |
+} |
+ |
+void AddCallbackToIOService(IONotificationPortRef port, |
+ const io_name_t type, |
+ CFMutableDictionaryRef dictionary, |
+ IOServiceMatchingCallback callback, |
+ void* context) { |
+ // Retain additional dictionary references because each call to |
+ // IOServiceAddMatchingNotification consumes one reference. |
+ dictionary = (CFMutableDictionaryRef)(CFRetain(dictionary)); |
Avi (use Gerrit)
2012/08/03 19:41:23
Huh? Just do
CFRetain(dictionary);
Why do you fe
no longer working on chromium
2012/08/06 09:43:12
From the silly example code, removed.
Avi (use Gerrit)
2012/08/06 13:54:37
This is not removed in the latest snapshot.
|
+ |
+ io_iterator_t devices_iterator = 0; |
+ kern_return_t err = IOServiceAddMatchingNotification(port, |
+ type, |
+ dictionary, |
+ callback, |
+ context, |
+ &devices_iterator); |
+ if (err) { |
+ NOTREACHED() << "Failed to register the IO mached notification for type " |
+ << type; |
+ return; |
+ } |
+ |
+ // Iterate over set of matching devices to access already-present devices |
+ // and to arm the notification. |
+ io_object_t thisObject; |
Avi (use Gerrit)
2012/08/03 19:41:23
base::mac::ScopedIOObject<io_object_t>? Also, this
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ while ((thisObject = IOIteratorNext(devices_iterator))) |
+ IOObjectRelease(thisObject); |
+} |
+ |
+} // namespace |
+ |
+DeviceMonitorMac::DeviceMonitorMac() { |
+ CFRunLoopRef runloop = CFRunLoopGetCurrent(); |
+ CFRetain(runloop); |
Avi (use Gerrit)
2012/08/03 19:41:23
Why the retain?
no longer working on chromium
2012/08/06 09:43:12
Sorry, uncleaned debugging code.
Avi (use Gerrit)
2012/08/06 13:54:37
This isn't fixed in the latest snapshot either.
|
+ |
+ // Add the notification port to the run loop. |
+ IONotificationPortRef notification_port = |
+ IONotificationPortCreate(kIOMasterPortDefault); |
Avi (use Gerrit)
2012/08/03 19:41:23
Where is the matching IONotificationPortDestroy?
no longer working on chromium
2012/08/06 09:43:12
Oh, thanks for pointing out, that example code I w
|
+ CFRunLoopSourceRef notification_cfsource = |
+ IONotificationPortGetRunLoopSource(notification_port); |
+ |
+ RegisterVideoCallbacks(notification_port); |
+ RegisterAudioCallbacks(notification_port); |
+ CFRunLoopAddSource(runloop, notification_cfsource, kCFRunLoopCommonModes); |
+} |
+ |
+void DeviceMonitorMac::RegisterVideoCallbacks(IONotificationPortRef port) { |
+ CFMutableDictionaryRef matching_dictionary = CreateMachingDictionary( |
+ kUSBVideoInterfaceClass, kUSBVideoControlSubClass); |
+ |
+ // Add a callback which will be called when a video device is plugged in. |
+ AddCallbackToIOService(port, |
+ kIOMatchedNotification, |
+ matching_dictionary, |
+ &VideoDeviceChangedCallback, |
+ this); |
+ |
+ |
+ // Add a callback which will be called when a video device is terminated. |
+ AddCallbackToIOService(port, |
+ kIOTerminatedNotification, |
+ matching_dictionary, |
+ &VideoDeviceChangedCallback, |
+ this); |
+} |
+ |
+void DeviceMonitorMac::RegisterAudioCallbacks(IONotificationPortRef port) { |
+ CFMutableDictionaryRef matching_dictionary = CreateMachingDictionary( |
+ kUSBAudioInterfaceClass, kUSBAudioControlSubClass); |
+ |
+ // Add a callback which will be called when a audio device is plugged in. |
+ AddCallbackToIOService(port, |
+ kIOMatchedNotification, |
+ matching_dictionary, |
+ &AudioDeviceChangedCallback, |
+ this); |
+ |
+ // Add a callback which will be called when a audio device is terminated. |
+ AddCallbackToIOService(port, |
+ kIOTerminatedNotification, |
+ matching_dictionary, |
+ &AudioDeviceChangedCallback, |
+ this); |
+} |
+ |
+void DeviceMonitorMac::VideoDeviceChangedCallback(void *context, |
+ io_iterator_t devices) { |
+ io_object_t thisObject; |
+ while ((thisObject = IOIteratorNext(devices))) { |
Avi (use Gerrit)
2012/08/03 19:41:23
See previous note about IOIteratorNext.
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ if (context) { |
+ InstanceFromContext(context)->NotifyDeviceChanged( |
+ base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
+ } |
+ IOObjectRelease(thisObject); |
+ } |
+} |
+ |
+void DeviceMonitorMac::AudioDeviceChangedCallback(void *context, |
+ io_iterator_t devices) { |
+ io_object_t thisObject; |
+ while ((thisObject = IOIteratorNext(devices))) { |
Avi (use Gerrit)
2012/08/03 19:41:23
Ditto.
no longer working on chromium
2012/08/06 09:43:12
Done.
|
+ if (context) { |
+ InstanceFromContext(context)->NotifyDeviceChanged( |
+ base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
+ } |
+ IOObjectRelease(thisObject); |
+ } |
+} |
+ |
+void DeviceMonitorMac::NotifyDeviceChanged( |
+ base::SystemMonitor::DeviceType type) { |
+ base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
+} |
+ |
+ |
+DeviceMonitorMac::~DeviceMonitorMac() {} |
+ |
+} // namespace content |