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 83namespace cricket { 84 85DeviceWatcherImpl* 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 100void 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 108bool 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 144bool 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