OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/mac/media_device_notifications.h" | |
6 | |
7 #include <Carbon/Carbon.h> | |
8 #include <CoreFoundation/CoreFoundation.h> | |
9 | |
10 #include "base/file_path.h" | |
11 #include "base/mac/foundation_util.h" | |
12 #include "base/mac/scoped_cftyperef.h" | |
13 #include "base/sys_string_conversions.h" | |
14 #include "base/system_monitor/system_monitor.h" | |
15 | |
16 namespace content { | |
17 | |
18 namespace { | |
19 | |
20 const CFStringRef kICAUserAssignedDeviceNameKey = | |
21 CFSTR("ICAUserAssignedDeviceNameKey"); | |
22 const CFStringRef kICDeviceNameKey = CFSTR("ifil"); | |
23 const CFStringRef kICDeviceBSDNameKey = CFSTR("bsdName"); | |
24 | |
25 CFStringRef CopyMountPointFromBSDName(CFStringRef bsd_name) { | |
26 base::mac::ScopedCFTypeRef<DASessionRef> session( | |
27 DASessionCreate(kCFAllocatorDefault)); | |
28 if (!session.get()) | |
29 return NULL; | |
30 | |
31 base::mac::ScopedCFTypeRef<DADiskRef> disk( | |
32 DADiskCreateFromBSDName(kCFAllocatorDefault, session.get(), | |
33 base::SysCFStringRefToUTF8(bsd_name).c_str())); | |
34 if (!disk.get()) | |
35 return NULL; | |
36 | |
37 base::mac::ScopedCFTypeRef<CFDictionaryRef> description( | |
38 DADiskCopyDescription(disk)); | |
39 if (!description.get()) | |
40 return NULL; | |
41 | |
42 CFURLRef mount_point = base::mac::GetValueFromDictionary<CFURLRef>( | |
43 description, kDADiskDescriptionVolumePathKey); | |
44 if (!mount_point) | |
45 return NULL; | |
46 | |
47 return CFURLCopyFileSystemPath(mount_point, kCFURLPOSIXPathStyle); | |
48 } | |
49 | |
50 bool GetDeviceInfo(unsigned long device_number, std::string* name, | |
51 FilePath* location) { | |
52 ICACopyObjectPropertyDictionaryPB properties_request; | |
53 properties_request.object = device_number; | |
54 CFDictionaryRef device_properties; | |
55 properties_request.theDict = &device_properties; | |
56 if (ICACopyObjectPropertyDictionary(&properties_request, NULL) != noErr) | |
57 return false; | |
58 base::mac::ScopedCFTypeRef<CFDictionaryRef> scoped_device_properties( | |
59 device_properties); | |
60 | |
61 CFStringRef device_name = base::mac::GetValueFromDictionary<CFStringRef>( | |
62 device_properties, kICAUserAssignedDeviceNameKey); | |
63 if (device_name == NULL) { | |
64 device_name = base::mac::GetValueFromDictionary<CFStringRef>( | |
65 device_properties, kICDeviceNameKey); | |
66 } | |
67 if (device_name == NULL) | |
68 return false; | |
69 *name = base::SysCFStringRefToUTF8(device_name); | |
70 | |
71 // TODO(vandebo) Support all media device, for now we only support mass | |
72 // storage media devices. | |
73 CFStringRef device = base::mac::GetValueFromDictionary<CFStringRef>( | |
74 device_properties, kICDeviceBSDNameKey); | |
75 if (device == NULL) | |
76 return false; | |
77 base::mac::ScopedCFTypeRef<CFStringRef> | |
78 path(CopyMountPointFromBSDName(device)); | |
79 if (path.get() == NULL) | |
80 return false; | |
81 | |
82 *location = FilePath(base::SysCFStringRefToUTF8(path).c_str()); | |
83 | |
84 return true; | |
85 } | |
86 | |
87 void MediaDeviceNotificationCallback(CFStringRef notification_type, | |
88 CFDictionaryRef notification_dictionary) { | |
89 bool attach = false; | |
90 if (CFEqual(notification_type, kICANotificationTypeDeviceAdded)) { | |
91 attach = true; | |
92 } else if (!CFEqual(notification_type, kICANotificationTypeDeviceRemoved)) { | |
93 return; | |
94 } | |
95 | |
96 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); | |
97 | |
98 CFNumberRef device_number_object = | |
99 base::mac::GetValueFromDictionary<CFNumberRef>( | |
100 notification_dictionary, kICANotificationDeviceICAObjectKey); | |
101 unsigned long device_number = | |
102 [base::mac::CFToNSCast(device_number_object) unsignedLongValue]; | |
103 if (attach) { | |
104 std::string device_name; | |
105 FilePath location; | |
106 if (GetDeviceInfo(device_number, &device_name, &location)) { | |
107 system_monitor->ProcessMediaDeviceAttached(device_number, device_name, | |
108 location); | |
109 } | |
110 } else { | |
111 system_monitor->ProcessMediaDeviceDetached(device_number); | |
112 } | |
113 } | |
114 | |
115 } // namespace | |
116 | |
117 void StartMediaDeviceNotifications() { | |
118 NSArray* events_of_interest = [NSArray arrayWithObjects: | |
119 (id)kICANotificationTypeDeviceAdded, | |
120 (id)kICANotificationTypeDeviceRemoved, | |
121 nil]; | |
122 | |
123 ICARegisterForEventNotificationPB notification_request; | |
124 notification_request.objectOfInterest = 0; // Zero means all objects | |
125 notification_request.eventsOfInterest = | |
126 base::mac::NSToCFCast(events_of_interest); | |
127 notification_request.notificationProc = &MediaDeviceNotificationCallback; | |
128 notification_request.options = NULL; | |
129 OSErr err = ICARegisterForEventNotification(¬ification_request, NULL); | |
130 CHECK_EQ(err, noErr); | |
131 } | |
132 | |
133 } // namespace content | |
OLD | NEW |