1 /* 2 * libjingle 3 * Copyright 2010 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 // support GCC compiler 29 #ifndef __has_feature 30 #define __has_feature(x) 0 31 #endif 32 33 #include "talk/media/devices/devicemanager.h" 34 35 #import <assert.h> 36 #ifdef __MAC_OS_X_VERSION_MAX_ALLOWED 37 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 38 #import <AVFoundation/AVFoundation.h> 39 #endif 40 #endif 41 #import <QTKit/QTKit.h> 42 43 #include "webrtc/base/logging.h" 44 45 @interface DeviceWatcherImpl : NSObject { 46 @private 47 cricket::DeviceManagerInterface* manager_; 48 } 49 - (id)init:(cricket::DeviceManagerInterface*)manager; 50 - (void)onDevicesChanged:(NSNotification*)notification; 51 @end 52 53 @implementation DeviceWatcherImpl 54 - (id)init:(cricket::DeviceManagerInterface*)manager { 55 if ((self = [super init])) { 56 assert(manager != NULL); 57 manager_ = manager; 58 [[NSNotificationCenter defaultCenter] 59 addObserver:self 60 selector:@selector(onDevicesChanged:) 61 name:QTCaptureDeviceWasConnectedNotification 62 object:nil]; 63 [[NSNotificationCenter defaultCenter] 64 addObserver:self 65 selector:@selector(onDevicesChanged:) 66 name:QTCaptureDeviceWasDisconnectedNotification 67 object:nil]; 68 } 69 return self; 70 } 71 72 - (void)dealloc { 73 [[NSNotificationCenter defaultCenter] removeObserver:self]; 74 #if !__has_feature(objc_arc) 75 [super dealloc]; 76 #endif 77 } 78 - (void)onDevicesChanged:(NSNotification*)notification { 79 manager_->SignalDevicesChange(); 80 } 81 @end 82 83 namespace cricket { 84 85 DeviceWatcherImpl* CreateDeviceWatcherCallback( 86 DeviceManagerInterface* manager) { 87 DeviceWatcherImpl* impl; 88 #if !__has_feature(objc_arc) 89 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 90 #else 91 @autoreleasepool 92 #endif 93 { impl = [[DeviceWatcherImpl alloc] init:manager]; } 94 #if !__has_feature(objc_arc) 95 [pool drain]; 96 #endif 97 return impl; 98 } 99 100 void ReleaseDeviceWatcherCallback(DeviceWatcherImpl* watcher) { 101 #if !__has_feature(objc_arc) 102 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 103 [watcher release]; 104 [pool drain]; 105 #endif 106 } 107 108 bool GetQTKitVideoDevices(std::vector<Device>* devices) { 109 #if !__has_feature(objc_arc) 110 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 111 #else 112 @autoreleasepool 113 #endif 114 { 115 NSArray* qt_capture_devices = 116 [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo]; 117 NSUInteger count = [qt_capture_devices count]; 118 LOG(LS_INFO) << count << " capture device(s) found:"; 119 for (QTCaptureDevice* qt_capture_device in qt_capture_devices) { 120 static NSString* const kFormat = @"localizedDisplayName: \"%@\", " 121 @"modelUniqueID: \"%@\", uniqueID \"%@\", isConnected: %d, " 122 @"isOpen: %d, isInUseByAnotherApplication: %d"; 123 NSString* info = [NSString 124 stringWithFormat:kFormat, 125 [qt_capture_device localizedDisplayName], 126 [qt_capture_device modelUniqueID], 127 [qt_capture_device uniqueID], 128 [qt_capture_device isConnected], 129 [qt_capture_device isOpen], 130 [qt_capture_device isInUseByAnotherApplication]]; 131 LOG(LS_INFO) << [info UTF8String]; 132 133 std::string name([[qt_capture_device localizedDisplayName] UTF8String]); 134 devices->push_back( 135 Device(name, [[qt_capture_device uniqueID] UTF8String])); 136 } 137 } 138 #if !__has_feature(objc_arc) 139 [pool drain]; 140 #endif 141 return true; 142 } 143 144 bool GetAVFoundationVideoDevices(std::vector<Device>* devices) { 145 #ifdef __MAC_OS_X_VERSION_MAX_ALLOWED 146 #if __MAC_OS_X_VERSION_MAX_ALLOWED >=1070 147 if (![AVCaptureDevice class]) { 148 // Fallback to using QTKit if AVFoundation is not available 149 return GetQTKitVideoDevices(devices); 150 } 151 #if !__has_feature(objc_arc) 152 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 153 #else 154 @autoreleasepool 155 #endif 156 { 157 NSArray* capture_devices = [AVCaptureDevice devices]; 158 LOG(LS_INFO) << [capture_devices count] << " capture device(s) found:"; 159 for (AVCaptureDevice* capture_device in capture_devices) { 160 if ([capture_device hasMediaType:AVMediaTypeVideo] || 161 [capture_device hasMediaType:AVMediaTypeMuxed]) { 162 static NSString* const kFormat = @"localizedName: \"%@\", " 163 @"modelID: \"%@\", uniqueID \"%@\", isConnected: %d, " 164 @"isInUseByAnotherApplication: %d"; 165 NSString* info = [NSString 166 stringWithFormat:kFormat, 167 [capture_device localizedName], 168 [capture_device modelID], 169 [capture_device uniqueID], 170 [capture_device isConnected], 171 [capture_device isInUseByAnotherApplication]]; 172 LOG(LS_INFO) << [info UTF8String]; 173 174 std::string name([[capture_device localizedName] UTF8String]); 175 devices->push_back( 176 Device(name, [[capture_device uniqueID] UTF8String])); 177 } 178 } 179 } 180 #if !__has_feature(objc_arc) 181 [pool drain]; 182 #endif 183 return true; 184 #else // __MAC_OS_X_VERSION_MAX_ALLOWED >=1070 185 return GetQTKitVideoDevices(devices); 186 #endif // __MAC_OS_X_VERSION_MAX_ALLOWED >=1070 187 #else // __MAC_OS_X_VERSION_MAX_ALLOWED 188 return GetQTKitVideoDevices(devices); 189 #endif // __MAC_OS_X_VERSION_MAX_ALLOWED 190 } 191 192 } // namespace cricket 193