Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(429)

Unified Diff: content/browser/device_monitor_mac.cc

Issue 10824162: add device notification to Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed linux bots. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « content/browser/device_monitor_mac.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698