Index: content/browser/mac/media_device_notifications.mm |
diff --git a/content/browser/mac/media_device_notifications.mm b/content/browser/mac/media_device_notifications.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..48d0b99791f8d302e140c22a7d583f1f35a32ef1 |
--- /dev/null |
+++ b/content/browser/mac/media_device_notifications.mm |
@@ -0,0 +1,133 @@ |
+// 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/mac/media_device_notifications.h" |
+ |
+#include <Carbon/Carbon.h> |
+#include <CoreFoundation/CoreFoundation.h> |
+ |
+#include "base/file_path.h" |
+#include "base/mac/foundation_util.h" |
+#include "base/mac/scoped_cftyperef.h" |
+#include "base/sys_string_conversions.h" |
+#include "base/system_monitor/system_monitor.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+const CFStringRef kICAUserAssignedDeviceNameKey = |
+ CFSTR("ICAUserAssignedDeviceNameKey"); |
+const CFStringRef kICDeviceNameKey = CFSTR("ifil"); |
+const CFStringRef kICDeviceBSDNameKey = CFSTR("bsdName"); |
+ |
+CFStringRef CopyMountPointFromBSDName(CFStringRef bsd_name) { |
+ base::mac::ScopedCFTypeRef<DASessionRef> session( |
+ DASessionCreate(kCFAllocatorDefault)); |
+ if (!session.get()) |
+ return NULL; |
+ |
+ base::mac::ScopedCFTypeRef<DADiskRef> disk( |
+ DADiskCreateFromBSDName(kCFAllocatorDefault, session.get(), |
+ base::SysCFStringRefToUTF8(bsd_name).c_str())); |
+ if (!disk.get()) |
+ return NULL; |
+ |
+ base::mac::ScopedCFTypeRef<CFDictionaryRef> description( |
+ DADiskCopyDescription(disk)); |
+ if (!description.get()) |
+ return NULL; |
+ |
+ CFURLRef mount_point = base::mac::GetValueFromDictionary<CFURLRef>( |
+ description, kDADiskDescriptionVolumePathKey); |
+ if (!mount_point) |
+ return NULL; |
+ |
+ return CFURLCopyFileSystemPath(mount_point, kCFURLPOSIXPathStyle); |
+} |
+ |
+bool GetDeviceInfo(unsigned long device_number, std::string* name, |
+ FilePath* location) { |
+ ICACopyObjectPropertyDictionaryPB properties_request; |
+ properties_request.object = device_number; |
+ CFDictionaryRef device_properties; |
+ properties_request.theDict = &device_properties; |
+ if (ICACopyObjectPropertyDictionary(&properties_request, NULL) != noErr) |
+ return false; |
+ base::mac::ScopedCFTypeRef<CFDictionaryRef> scoped_device_properties( |
+ device_properties); |
+ |
+ CFStringRef device_name = base::mac::GetValueFromDictionary<CFStringRef>( |
+ device_properties, kICAUserAssignedDeviceNameKey); |
+ if (device_name == NULL) { |
+ device_name = base::mac::GetValueFromDictionary<CFStringRef>( |
+ device_properties, kICDeviceNameKey); |
+ } |
+ if (device_name == NULL) |
+ return false; |
+ *name = base::SysCFStringRefToUTF8(device_name); |
+ |
+ // TODO(vandebo) Support all media device, for now we only support mass |
+ // storage media devices. |
+ CFStringRef device = base::mac::GetValueFromDictionary<CFStringRef>( |
+ device_properties, kICDeviceBSDNameKey); |
+ if (device == NULL) |
+ return false; |
+ base::mac::ScopedCFTypeRef<CFStringRef> |
+ path(CopyMountPointFromBSDName(device)); |
+ if (path.get() == NULL) |
+ return false; |
+ |
+ *location = FilePath(base::SysCFStringRefToUTF8(path).c_str()); |
+ |
+ return true; |
+} |
+ |
+void MediaDeviceNotificationCallback(CFStringRef notification_type, |
+ CFDictionaryRef notification_dictionary) { |
+ bool attach = false; |
+ if (CFEqual(notification_type, kICANotificationTypeDeviceAdded)) { |
+ attach = true; |
+ } else if (!CFEqual(notification_type, kICANotificationTypeDeviceRemoved)) { |
+ return; |
+ } |
+ |
+ base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); |
+ |
+ CFNumberRef device_number_object = |
+ base::mac::GetValueFromDictionary<CFNumberRef>( |
+ notification_dictionary, kICANotificationDeviceICAObjectKey); |
+ unsigned long device_number = |
+ [base::mac::CFToNSCast(device_number_object) unsignedLongValue]; |
+ if (attach) { |
+ std::string device_name; |
+ FilePath location; |
+ if (GetDeviceInfo(device_number, &device_name, &location)) { |
+ system_monitor->ProcessMediaDeviceAttached(device_number, device_name, |
+ location); |
+ } |
+ } else { |
+ system_monitor->ProcessMediaDeviceDetached(device_number); |
+ } |
+} |
+ |
+} // namespace |
+ |
+void StartMediaDeviceNotifications() { |
+ NSArray* events_of_interest = [NSArray arrayWithObjects: |
+ (id)kICANotificationTypeDeviceAdded, |
+ (id)kICANotificationTypeDeviceRemoved, |
+ nil]; |
+ |
+ ICARegisterForEventNotificationPB notification_request; |
+ notification_request.objectOfInterest = 0; // Zero means all objects |
+ notification_request.eventsOfInterest = |
+ base::mac::NSToCFCast(events_of_interest); |
+ notification_request.notificationProc = &MediaDeviceNotificationCallback; |
+ notification_request.options = NULL; |
+ OSErr err = ICARegisterForEventNotification(¬ification_request, NULL); |
+ CHECK_EQ(err, noErr); |
+} |
+ |
+} // namespace content |