| 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..eefe0394984d82457ef0dce769d579f276d961a9
|
| --- /dev/null
|
| +++ b/content/browser/device_monitor_mac.cc
|
| @@ -0,0 +1,167 @@
|
| +// 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 {
|
| +
|
| +const io_name_t kServices[] = {
|
| + kIOFirstPublishNotification,
|
| + kIOTerminatedNotification,
|
| +};
|
| +
|
| +CFMutableDictionaryRef CreateMatchingDictionaryForUSBDevices(
|
| + 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 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() {
|
| + // 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 notification port from the message runloop.
|
| + CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
|
| + IONotificationPortGetRunLoopSource(notification_port_),
|
| + kCFRunLoopCommonModes);
|
| +
|
| + // Destroy the notification port allocated by IONotificationPortCreate.
|
| + IONotificationPortDestroy(notification_port_);
|
| +}
|
| +
|
| +void DeviceMonitorMac::RegisterAudioServices() {
|
| + CFMutableDictionaryRef dictionary =
|
| + IOServiceMatching(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) {
|
| + // |dictionary| comes in with a reference count as 1. Since each call to
|
| + // IOServiceAddMatchingNotification consumes one reference, we need to
|
| + // retain |arraysize(kServices) -1| additional dictionary references.
|
| + 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
|
|
|