Chromium Code Reviews| 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..df9061e5a89f561db3af081b8c33d6e37f41557e |
| --- /dev/null |
| +++ b/content/browser/device_monitor_mac.mm |
| @@ -0,0 +1,163 @@ |
| +// 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> |
|
Avi (use Gerrit)
2012/08/06 13:54:37
You don't need to include this; the include below
no longer working on chromium
2012/08/06 19:53:12
Done.
|
| +#include <CoreFoundation/CoreFoundation.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 { |
| + |
| +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) { |
| + // Retain additional dictionary references because each call to |
| + // IOServiceAddMatchingNotification consumes one reference. |
| + dictionary = (CFMutableDictionaryRef)(CFRetain(dictionary)); |
|
Avi (use Gerrit)
2012/08/06 13:54:37
I already commented on this. Why do you feel you n
no longer working on chromium
2012/08/06 19:53:12
I should have removed it from the previous set of
|
| + |
| + io_iterator_t devices_iterator = 0; |
|
Avi (use Gerrit)
2012/08/06 13:54:37
The iterator itself needs to be a base::mac::Scope
no longer working on chromium
2012/08/06 19:53:12
Thanks for pointing out, this does leak.
I have to
|
| + kern_return_t err = IOServiceAddMatchingNotification(port, |
| + type, |
| + dictionary, |
| + callback, |
| + context, |
| + &devices_iterator); |
| + if (err) { |
| + NOTREACHED() << "Failed to register the IO mached notification for type " |
|
Avi (use Gerrit)
2012/08/06 13:54:37
s/mached/matched/
no longer working on chromium
2012/08/06 19:53:12
Done.
|
| + << type; |
| + return; |
| + } |
| + |
| + // 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(devices_iterator)); |
| + for (; this_object; this_object.reset(IOIteratorNext(devices_iterator))); |
|
Avi (use Gerrit)
2012/08/06 13:54:37
Do we want to do something with the objects we're
no longer working on chromium
2012/08/06 19:53:12
My understanding here is simply loop through the e
Avi (use Gerrit)
2012/08/06 20:29:47
Do we need to fire a first-time changed callback?
no longer working on chromium
2012/08/06 22:01:10
This for loop does the same as calling a first-tim
|
| +} |
| + |
| +void RegisterCallbacks(IONotificationPortRef port, |
| + CFMutableDictionaryRef dictionary, |
| + IOServiceMatchingCallback callback, |
| + void* context) { |
| + // Add a callback which will be called when a video device is plugged in. |
| + AddCallbackToIOService(port, |
| + kIOMatchedNotification, |
| + dictionary, |
| + callback, |
| + context); |
| + |
| + // Add a callback which will be called when a video device is terminated. |
| + AddCallbackToIOService(port, |
| + kIOTerminatedNotification, |
| + dictionary, |
| + callback, |
| + context); |
| +} |
| + |
| +} // namespace |
| + |
| +DeviceMonitorMac::DeviceMonitorMac() { |
| + CFRunLoopRef runloop = CFRunLoopGetCurrent(); |
| + CFRetain(runloop); |
|
Avi (use Gerrit)
2012/08/06 13:54:37
Why are you retaining this? Please address my earl
no longer working on chromium
2012/08/06 19:53:12
This should have been removed too. Sorry.
|
| + |
| + // Add the notification port to the run loop. |
| + notification_port_ = IONotificationPortCreate(kIOMasterPortDefault); |
| + DCHECK(notification_port_); |
| + CFRunLoopSourceRef notification_cfsource = |
| + IONotificationPortGetRunLoopSource(notification_port_); |
| + |
| + RegisterVideoCallbacks(); |
| + RegisterAudioCallbacks(); |
| + CFRunLoopAddSource(runloop, notification_cfsource, kCFRunLoopCommonModes); |
| +} |
| + |
| +DeviceMonitorMac::~DeviceMonitorMac() { |
| + // 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::RegisterVideoCallbacks() { |
| + CFMutableDictionaryRef matching_dictionary = CreateMatchingDictionary( |
| + kUSBVideoInterfaceClass, kUSBVideoControlSubClass); |
| + |
| + RegisterCallbacks(notification_port_, |
| + matching_dictionary, |
| + &VideoDeviceChangedCallback, |
| + this); |
| +} |
| + |
| +void DeviceMonitorMac::RegisterAudioCallbacks() { |
| + CFMutableDictionaryRef matching_dictionary = CreateMatchingDictionary( |
| + kUSBAudioInterfaceClass, kUSBAudioControlSubClass); |
| + |
| + RegisterCallbacks(notification_port_, |
| + matching_dictionary, |
| + &AudioDeviceChangedCallback, |
| + this); |
| +} |
| + |
| +void DeviceMonitorMac::VideoDeviceChangedCallback(void *context, |
| + io_iterator_t devices) { |
| + base::mac::ScopedIOObject<io_service_t> this_object(IOIteratorNext(devices)); |
| + for (; this_object; this_object.reset(IOIteratorNext(devices))) { |
| + if (context) { |
| + reinterpret_cast<DeviceMonitorMac*>(context)->NotifyDeviceChanged( |
| + base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
| + } |
| + IOObjectRelease(this_object); |
|
Avi (use Gerrit)
2012/08/06 13:54:37
Wha? No, the ScopedIOObject releases.
no longer working on chromium
2012/08/06 19:53:12
Done.
|
| + } |
| +} |
| + |
| +void DeviceMonitorMac::AudioDeviceChangedCallback(void *context, |
| + io_iterator_t devices) { |
| + base::mac::ScopedIOObject<io_service_t> this_object(IOIteratorNext(devices)); |
| + for (; this_object; this_object.reset(IOIteratorNext(devices))) { |
| + if (context) { |
| + reinterpret_cast<DeviceMonitorMac*>(context)->NotifyDeviceChanged( |
| + base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
| + } |
| + IOObjectRelease(this_object); |
|
Avi (use Gerrit)
2012/08/06 13:54:37
Ditto.
no longer working on chromium
2012/08/06 19:53:12
Done.
|
| + } |
| +} |
| + |
| +void DeviceMonitorMac::NotifyDeviceChanged( |
| + base::SystemMonitor::DeviceType type) { |
| + base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
| +} |
| + |
| +} // namespace content |