Chromium Code Reviews| 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..0ca48cf68d8f19398be1338d8b0b57edca98ecd6 |
| --- /dev/null |
| +++ b/content/browser/device_monitor_mac.cc |
| @@ -0,0 +1,166 @@ |
| +// 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/audio/IOAudioDefines.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 { |
|
Mark Mentovai
2012/08/14 15:37:05
We also usually put a blank line after opening a n
no longer working on chromium
2012/08/14 15:59:36
Done.
|
| +const io_name_t kServices[] = { |
| + kIOFirstPublishNotification, |
| + kIOTerminatedNotification, |
| +}; |
| + |
| +CFMutableDictionaryRef CreateMatchingDictionaryForUSBDevices( |
| + SInt32 interface_class_code, SInt32 interface_subclass_code) { |
| + CFMutableDictionaryRef matching_dictionary = IOServiceMatching( |
|
Mark Mentovai
2012/08/14 15:37:05
This is more legible when you break the line after
no longer working on chromium
2012/08/14 15:59:36
Done.
|
| + 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 RegisterCallbackToIOService(IONotificationPortRef port, |
| + const io_name_t type, |
| + CFMutableDictionaryRef dictionary, |
| + IOServiceMatchingCallback callback, |
| + void* context, |
| + io_iterator_t* service) { |
| + kern_return_t err = IOServiceAddMatchingNotification(port, |
| + type, |
| + dictionary, |
| + callback, |
| + context, |
| + service); |
| + if (err) { |
| + NOTREACHED() << "Failed to register the IO matched notification for type " |
| + << type; |
| + return; |
| + } |
| + DCHECK(*service); |
| + |
| + // Iterate over set of matching devices to access already-present devices |
| + // and to arm the notification. |
| + for (base::mac::ScopedIOObject<io_service_t> object(IOIteratorNext(*service)); |
| + object; |
| + object.reset(IOIteratorNext(*service))) {}; |
| +} |
| + |
| +} // namespace |
| + |
| +DeviceMonitorMac::DeviceMonitorMac() { |
| + |
|
Mark Mentovai
2012/08/14 15:37:05
But we don’t usually begin functions (or construct
no longer working on chromium
2012/08/14 15:59:36
Done.
|
| + // Add the notification port to the run loop. |
| + notification_port_ = IONotificationPortCreate(kIOMasterPortDefault); |
| + DCHECK(notification_port_); |
| + |
| + RegisterAudioServices(); |
| + RegisterVideoServices(); |
| + |
| + CFRunLoopAddSource(CFRunLoopGetCurrent(), |
| + IONotificationPortGetRunLoopSource(notification_port_), |
| + kCFRunLoopCommonModes); |
| +} |
| + |
| +DeviceMonitorMac::~DeviceMonitorMac() { |
| + // Stop the notifications and free the objects. |
| + for (size_t i = 0; i < notification_iterators_.size(); ++i) { |
| + IOObjectRelease(*notification_iterators_[i]); |
| + } |
| + notification_iterators_.clear(); |
| + |
| + // Remove the sleep notification port from the application runloop. |
|
Mark Mentovai
2012/08/14 15:37:05
This seems like a copy-paste job. This code has no
no longer working on chromium
2012/08/14 15:59:36
Done.
|
| + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), |
| + IONotificationPortGetRunLoopSource(notification_port_), |
| + kCFRunLoopCommonModes); |
| + |
| + // Destroy the notification port allocated by IONotificationPortCreate. |
| + IONotificationPortDestroy(notification_port_); |
| +} |
| + |
| +void DeviceMonitorMac::RegisterAudioServices() { |
| + CFMutableDictionaryRef dictionary = IOServiceMatching( |
|
Mark Mentovai
2012/08/14 15:37:05
Rewrap for readability as I suggested on line 24.
no longer working on chromium
2012/08/14 15:59:36
Done.
|
| + kIOAudioDeviceClassName); |
| + RegisterServices(dictionary, &AudioDeviceCallback); |
| +} |
| + |
| +void DeviceMonitorMac::RegisterVideoServices() { |
| + CFMutableDictionaryRef dictionary = CreateMatchingDictionaryForUSBDevices( |
| + kUSBVideoInterfaceClass, kUSBVideoControlSubClass); |
| + RegisterServices(dictionary, &VideoDeviceCallback); |
| +} |
| + |
| +void DeviceMonitorMac::RegisterServices(CFMutableDictionaryRef dictionary, |
| + IOServiceMatchingCallback callback) { |
| + // Add callback to the service. |
| + for (size_t i = 0; i < arraysize(kServices); ++i) { |
| + // Retain |arraysize(kServices) -1| additional dictionary references because |
|
Mark Mentovai
2012/08/14 15:37:05
I don’t understand why you only do this for arrays
no longer working on chromium
2012/08/14 15:59:36
When creating the CFMutableDictionaryRef, the ref
Mark Mentovai
2012/08/14 16:02:53
xians1 wrote:
|
| + // each call to IOServiceAddMatchingNotification consumes one reference. |
| + if (i < (arraysize(kServices) - 1)) |
| + CFRetain(dictionary); |
| + |
| + // Register callback to each service. |
| + io_iterator_t service; |
| + RegisterCallbackToIOService(notification_port_, |
| + kServices[i], |
| + dictionary, |
| + callback, |
| + this, |
| + &service); |
| + |
| + // Store the pointer of the object to release the memory when shutting |
| + // down the services. |
| + notification_iterators_.push_back(&service); |
| + } |
| +} |
| + |
| +void DeviceMonitorMac::AudioDeviceCallback(void *context, |
| + io_iterator_t iterator) { |
| + for (base::mac::ScopedIOObject<io_service_t> object(IOIteratorNext(iterator)); |
| + object; |
| + object.reset(IOIteratorNext(iterator))) { |
| + if (context) { |
| + reinterpret_cast<DeviceMonitorMac*>(context)->NotifyDeviceChanged( |
| + base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
| + } |
| + } |
| +} |
| + |
| +void DeviceMonitorMac::VideoDeviceCallback(void *context, |
| + io_iterator_t iterator) { |
| + for (base::mac::ScopedIOObject<io_service_t> object(IOIteratorNext(iterator)); |
| + object; |
| + object.reset(IOIteratorNext(iterator))) { |
| + if (context) { |
| + reinterpret_cast<DeviceMonitorMac*>(context)->NotifyDeviceChanged( |
| + base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
| + } |
| + } |
| +} |
| + |
| +void DeviceMonitorMac::NotifyDeviceChanged( |
| + base::SystemMonitor::DeviceType type) { |
| + // TODO(xians): Remove the global variable for SystemMonitor. |
| + base::SystemMonitor::Get()->ProcessDevicesChanged(type); |
| +} |
| + |
| +} // namespace content |