Chromium Code Reviews| 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..7e50e20912064ff95fa61589d6edca569f4f71c5 |
| --- /dev/null |
| +++ b/content/browser/mac/media_device_notifications.mm |
| @@ -0,0 +1,132 @@ |
| +// 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 = |
| + base::mac::NSToCFCast(@"ICAUserAssignedDeviceNameKey"); |
|
Avi (use Gerrit)
2012/02/28 01:26:46
CFSTR() here and the next two lines.
vandebo (ex-Chrome)
2012/02/28 18:35:05
Done.
|
| +const CFStringRef kICDeviceNameKey = base::mac::NSToCFCast(@"ifil"); |
| +const CFStringRef kICDeviceBSDNameKey = base::mac::NSToCFCast(@"bsdName"); |
| + |
| +CFStringRef CopyMountPointFromBSDName(const char* bsd_name) { |
|
Avi (use Gerrit)
2012/02/28 01:26:46
It's weird that this doesn't take a CF argument bu
vandebo (ex-Chrome)
2012/02/28 18:35:05
Done.
|
| + base::mac::ScopedCFTypeRef<DASessionRef> session( |
| + DASessionCreate(kCFAllocatorDefault)); |
| + if (!session.get()) |
| + return NULL; |
| + |
| + base::mac::ScopedCFTypeRef<DADiskRef> disk( |
| + DADiskCreateFromBSDName(kCFAllocatorDefault, session.get(), bsd_name)); |
| + 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, kCFURLComponentPath); |
|
Avi (use Gerrit)
2012/02/28 01:26:46
You mean kCFURLPOSIXPathStyle. (kCFURLComponentPat
vandebo (ex-Chrome)
2012/02/28 18:35:05
Done.
|
| +} |
| + |
| +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; |
| + OSErr ret = ICACopyObjectPropertyDictionary(&properties_request, NULL); |
| + base::mac::ScopedCFTypeRef<CFDictionaryRef> scoped_device_properties( |
| + device_properties); |
| + CHECK_EQ(ret, noErr); |
|
Avi (use Gerrit)
2012/02/28 01:26:46
Everywhere else, if a null is returned you return
vandebo (ex-Chrome)
2012/02/28 18:35:05
Done.
|
| + |
| + 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(base::SysCFStringRefToUTF8(device).c_str())); |
| + 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; |
|
Avi (use Gerrit)
2012/02/28 01:26:46
A little confused; why the return here? If you don
vandebo (ex-Chrome)
2012/02/28 18:35:05
A conversion bug, from CFStringCompare. I would h
|
| + } |
| + |
| + 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, |
| + NULL]; |
|
Avi (use Gerrit)
2012/02/28 01:26:46
nil (not NULL) is used when referring to an ObjC o
vandebo (ex-Chrome)
2012/02/28 18:35:05
Done.
|
| + |
| + 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 |