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..dfc6ca1c65d1bf67a0737c9d178dbffdabc62831 |
| --- /dev/null |
| +++ b/content/browser/device_monitor_mac.mm |
| @@ -0,0 +1,174 @@ |
| +// 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 "base/logging.h" |
| +#include "base/system_monitor/system_monitor.h" |
| + |
| +#include <CoreFoundation/CFNumber.h> |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
shouldn't these be above the chrome includes?
no longer working on chromium
2012/08/03 13:07:07
done.
|
| +#include <CoreFoundation/CoreFoundation.h> |
| +#include <IOKit/usb/IOUSBLib.h> |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +DeviceMonitorMac* InstanceFromContext(void* context) { |
| + return reinterpret_cast<DeviceMonitorMac*>(context); |
| +} |
| + |
| +void AddValueToDictionary(CFMutableDictionaryRef dictionary, |
| + SInt32 code, |
| + const void *key) { |
| + CFNumberRef number_ref = CFNumberCreate(kCFAllocatorDefault, |
| + kCFNumberSInt32Type, |
| + &code); |
| + if (!number_ref) { |
| + NOTREACHED() << "failed to create CFNumberRef for " << code; |
| + return; |
| + } |
| + |
| + CFDictionaryAddValue(dictionary, key, number_ref); |
| + CFRelease(number_ref); |
| + |
| + dictionary = (CFMutableDictionaryRef)(CFRetain(dictionary)); |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
fix cast or is this how things are done in mm land
no longer working on chromium
2012/08/03 13:07:07
neither static_cast nor reinterpret_cast passes th
|
| +} |
| + |
| +void VideoDeviceChangedCallback(void *context, io_iterator_t devices) { |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
void* context.
In order to allow this method to c
no longer working on chromium
2012/08/03 13:07:07
Done.
|
| + io_object_t thisObject; |
| + while ((thisObject = IOIteratorNext(devices))) { |
| + if (context) |
| + InstanceFromContext(context)->NotifyVideoDeviceChanged(); |
| + |
| + IOObjectRelease(thisObject); |
| + } |
| +} |
| + |
| +void AudioDeviceChangedCallback(void *context, io_iterator_t devices) { |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
same as above.
no longer working on chromium
2012/08/03 13:07:07
Done.
|
| + io_object_t thisObject; |
| + while ((thisObject = IOIteratorNext(devices))) { |
| + if (context) |
| + InstanceFromContext(context)->NotifyAudioDeviceChanged(); |
| + |
| + IOObjectRelease(thisObject); |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +DeviceMonitorMac::DeviceMonitorMac() { |
| + CFRunLoopRef runloop = CFRunLoopGetCurrent (); |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
no space before ()
no longer working on chromium
2012/08/03 13:07:07
Done.
|
| + CFRetain (runloop); |
| + |
| + // Add the notification port to the run loop. |
| + IONotificationPortRef notification_port = |
| + IONotificationPortCreate (kIOMasterPortDefault); |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
same here. please fix throughout
no longer working on chromium
2012/08/03 13:07:07
Done.
|
| + CFRunLoopSourceRef notification_cfsource = |
| + IONotificationPortGetRunLoopSource (notification_port); |
| + |
| + RegisterVideoCallbacks(notification_port); |
| + RegisterAudioCallbacks(notification_port); |
| + CFRunLoopAddSource(runloop, notification_cfsource, kCFRunLoopCommonModes); |
| +} |
| + |
| +void DeviceMonitorMac::RegisterVideoCallbacks(IONotificationPortRef port) { |
| + SInt32 interface_class_code = kUSBVideoInterfaceClass; |
| + SInt32 interface_subclass_code = kUSBVideoControlSubClass; |
| + CFMutableDictionaryRef matching_dictionary = IOServiceMatching( |
| + kIOUSBInterfaceClassName); |
| + AddValueToDictionary(matching_dictionary, interface_class_code, |
| + CFSTR(kUSBInterfaceClass)); |
| + AddValueToDictionary(matching_dictionary, interface_subclass_code, |
| + CFSTR(kUSBInterfaceSubClass)); |
| + |
| + // Add a callback which will be called when a video device is plugged in. |
| + io_iterator_t new_devices_iterator = 0; |
| + kern_return_t err = IOServiceAddMatchingNotification( |
| + port, |
| + kIOMatchedNotification, |
| + matching_dictionary, |
| + &VideoDeviceChangedCallback, |
| + this, |
| + &new_devices_iterator); |
| + if (err) { |
| + NOTREACHED() << "Failed to register the video IO mached notification"; |
| + return; |
| + } |
| + VideoDeviceChangedCallback(NULL, new_devices_iterator); |
| + |
| + // Add a callback which will be called when a video device is terminated. |
| + io_iterator_t lost_devices_iterator = 0; |
| + err = IOServiceAddMatchingNotification( |
| + port, |
| + kIOTerminatedNotification, |
| + matching_dictionary, |
| + &VideoDeviceChangedCallback, |
| + this, |
| + &lost_devices_iterator); |
| + if (err) { |
| + NOTREACHED() << "Failed to register the video IO terminated notification"; |
| + return; |
| + } |
| + VideoDeviceChangedCallback(NULL, lost_devices_iterator); |
| +} |
| + |
| +void DeviceMonitorMac::RegisterAudioCallbacks(IONotificationPortRef port) { |
| + SInt32 interface_class_code = kUSBAudioInterfaceClass; |
| + SInt32 interface_subclass_code = kUSBAudioControlSubClass; |
| + CFMutableDictionaryRef matching_dictionary = IOServiceMatching( |
| + kIOUSBInterfaceClassName); |
| + AddValueToDictionary(matching_dictionary, interface_class_code, |
| + CFSTR(kUSBInterfaceClass)); |
| + AddValueToDictionary(matching_dictionary, interface_subclass_code, |
| + CFSTR(kUSBInterfaceSubClass)); |
| + |
| + // Add a callback which will be called when a audio device is plugged in. |
| + io_iterator_t added_devices_iterator = 0; |
| + kern_return_t err = IOServiceAddMatchingNotification( |
| + port, |
| + kIOMatchedNotification, |
| + matching_dictionary, |
| + &AudioDeviceChangedCallback, |
| + this, |
| + &added_devices_iterator); |
| + if (err) { |
| + NOTREACHED() << "Failed to register the audio IO mached notification"; |
| + return; |
| + } |
| + // Iterate over set of matching devices to access already-present devices |
| + // and to arm the notification. |
| + AudioDeviceChangedCallback(NULL, added_devices_iterator); |
| + |
| + // Add a callback which will be called when a audio device is terminated. |
| + io_iterator_t removed_devices_iterator = 0; |
| + err = IOServiceAddMatchingNotification( |
| + port, |
| + kIOTerminatedNotification, |
| + matching_dictionary, |
| + &AudioDeviceChangedCallback, |
| + this, |
| + &removed_devices_iterator); |
| + if (err) { |
| + NOTREACHED() << "Failed to register the audio IO terminated notification"; |
|
tommi (sloooow) - chröme
2012/08/03 11:24:29
fix indent
no longer working on chromium
2012/08/03 13:07:07
Done.
|
| + return; |
| + } |
| + // Iterate over set of matching devices to release each one and to |
| + // arm the notification. |
| + AudioDeviceChangedCallback(NULL, removed_devices_iterator); |
| +} |
| + |
| +void DeviceMonitorMac::NotifyAudioDeviceChanged() { |
| + base::SystemMonitor* monitor = base::SystemMonitor::Get(); |
| + monitor->ProcessDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); |
| +} |
| + |
| +void DeviceMonitorMac::NotifyVideoDeviceChanged() { |
| + base::SystemMonitor* monitor = base::SystemMonitor::Get(); |
| + monitor->ProcessDevicesChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); |
| +} |
| + |
| +DeviceMonitorMac::~DeviceMonitorMac() {} |
| + |
| +} // namespace content |