home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 114 / macaddict114.cdr / Software / Utilities / macam.0.8.4.dmg / macam sources / driver_core / MyCameraCentral.m < prev    next >
Encoding:
Text File  |  2005-11-16  |  27.9 KB  |  785 lines

  1. /*
  2.  macam - webcam app and QuickTime driver component
  3.  Copyright (C) 2002 Matthias Krauss (macam@matthias-krauss.de)
  4.  
  5.  This program is free software; you can redistribute it and/or modify
  6.  it under the terms of the GNU General Public License as published by
  7.  the Free Software Foundation; either version 2 of the License, or
  8.  (at your option) any later version.
  9.  
  10.  This program is distributed in the hope that it will be useful,
  11.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  GNU General Public License for more details.
  14.  
  15.  You should have received a copy of the GNU General Public License
  16.  along with this program; if not, write to the Free Software
  17.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  $Id: MyCameraCentral.m,v 1.28 2005/11/14 20:46:32 hxr Exp $
  19.  */
  20.  
  21. #include <CoreFoundation/CoreFoundation.h>
  22. #include <IOKit/IOKitLib.h>
  23. #include <IOKit/IOMessage.h>
  24. #include <IOKit/IOCFPlugIn.h>
  25. #include <IOKit/usb/IOUSBLib.h>
  26. #include "MiscTools.h"
  27. #import "MyCameraInfo.h"
  28. #import "MyCameraCentral.h"
  29. #import "MyCameraDriver.h"
  30. #import "MyKiaraFamilyDriver.h"
  31. #import "MyKiaraFlippedDriver.h"
  32. #import "MyTimonFamilyDriver.h"
  33. #import "MyCPIACameraDriver.h"
  34. #import "MyQX3Driver.h"
  35. #import "MySTV680Driver.h"
  36. #import "MyIntelPCCameraPro.h"
  37. #import "MyDummyCameraDriver.h"
  38. #import "MyQCExpressADriver.h"
  39. #import "MyQCExpressBDriver.h"
  40. #import "MyQCWebDriver.h"
  41. #import "MyVicamDriver.h"
  42. #import "MySPCA504Driver.h"
  43. #import "MyOV511Driver.h"
  44. #import "MySonix2028Driver.h"
  45. #import "MySE401Driver.h"
  46. #import "MyQCProBeigeDriver.h"
  47. #import "MySPCA500Driver.h"
  48. #import "MyQCOrbitDriver.h"
  49. #import "SQ905.h"
  50. #include "unistd.h"
  51.     
  52.  
  53. void DeviceAdded(void *refCon, io_iterator_t iterator);
  54.  
  55. static NSString* driverBundleName=@"net.sourceforge.webcam-osx.common";
  56. static NSMutableDictionary* prefsDict=NULL;
  57. MyCameraCentral* sharedCameraCentral=NULL;
  58.  
  59.  
  60. @interface MyCameraCentral (Private)
  61.  
  62. //Internal preferences handling. We cannot use NSUserDefaults here because we might be in someone else's bundle (in a lib)
  63. - (id) prefsForKey:(NSString*) key;
  64. - (void) setPrefs:(id)prefs forKey:(NSString*)key;
  65. - (void) registerCameraDriver:(Class)driver;
  66. - (CameraError) locationIdOfUSBDeviceRef:(io_service_t)usbDeviceRef to:(UInt32*)outVal;
  67.  
  68. @end
  69.     
  70.  
  71. @implementation MyCameraCentral
  72.  
  73.  
  74. //MyCameraCentral is a singleton. Use this function to get the shared instance
  75. + (MyCameraCentral*) sharedCameraCentral {
  76.     if (!sharedCameraCentral) sharedCameraCentral=[[MyCameraCentral alloc] init];
  77.     return sharedCameraCentral;
  78. }
  79.  
  80. //See if someone has requested MyCameraCentral before
  81. + (BOOL) isCameraCentralExisting {
  82.     return (sharedCameraCentral!=NULL)?YES:NO;
  83. }
  84.  
  85.  
  86. //Localization for driver-specific stuff. As a component, the standard stuff won't work...
  87.  
  88. + (NSString*) localizedStringFor:(NSString*) str {
  89.     NSBundle* bundle=[NSBundle bundleForClass:[self class]];
  90.     NSString* ret=[bundle localizedStringForKey:str value:@"" table:@"DriverLocalizable"];
  91.     return ret;
  92. }
  93.  
  94. + (void) localizedCStrFor:(char*)cKey into:(char*)cValue {
  95.     NSAutoreleasePool* pool;
  96.     NSString* string;
  97.     const char* tmpCStr;
  98.     if (!cValue) return;
  99.     if (!cKey) return;
  100.     pool=[[NSAutoreleasePool alloc] init];
  101.     string=[NSString stringWithCString:cKey];
  102.     string=[self localizedStringFor:string];
  103.     tmpCStr=[string lossyCString];
  104.     CStr2CStr(tmpCStr,cValue);    //Note: No bounds check! Don't write dramas...
  105.     [pool release];
  106. }
  107.  
  108. - (char*) localizedCStrForError:(CameraError)err {
  109.     char* cstr;
  110.     switch (err) {
  111.         case CameraErrorOK:
  112.         case CameraErrorBusy:
  113.         case CameraErrorNoPower:
  114.         case CameraErrorNoCam:
  115.         case CameraErrorNoMem:
  116.         case CameraErrorNoBandwidth:
  117.         case CameraErrorTimeout:
  118.         case CameraErrorUSBProblem:
  119.         case CameraErrorInternal:
  120.             cstr=localizedErrorCStrs[err];
  121.             break;
  122.         default:
  123.             cstr=localizedUnknownErrorCStr;
  124.             break;
  125.     }
  126.     return cstr;
  127. }
  128.     
  129.  
  130. //Init, startup, shutdown, dealloc
  131.  
  132. - (id) init {
  133.     [super init];
  134.     cameraTypes=[[NSMutableArray alloc] initWithCapacity:10];
  135.     cameras=[[NSMutableArray alloc] initWithCapacity:10];
  136.     delegate=NULL;
  137.  
  138.     //Cache localized error codes
  139.     [[self class] localizedCStrFor:"CameraErrorOK" into:localizedErrorCStrs[CameraErrorOK]];
  140.     [[self class] localizedCStrFor:"CameraErrorBusy" into:localizedErrorCStrs[CameraErrorBusy]];
  141.     [[self class] localizedCStrFor:"CameraErrorNoPower" into:localizedErrorCStrs[CameraErrorNoPower]];
  142.     [[self class] localizedCStrFor:"CameraErrorNoCam" into:localizedErrorCStrs[CameraErrorNoCam]];
  143.     [[self class] localizedCStrFor:"CameraErrorNoMem" into:localizedErrorCStrs[CameraErrorNoMem]];
  144.     [[self class] localizedCStrFor:"CameraErrorNoBandwidth" into:localizedErrorCStrs[CameraErrorNoBandwidth]];
  145.     [[self class] localizedCStrFor:"CameraErrorTimeout" into:localizedErrorCStrs[CameraErrorTimeout]];
  146.     [[self class] localizedCStrFor:"CameraErrorUSBProblem" into:localizedErrorCStrs[CameraErrorUSBProblem]];
  147.     [[self class] localizedCStrFor:"CameraErrorUnimplemented" into:localizedErrorCStrs[CameraErrorUnimplemented]];
  148.     [[self class] localizedCStrFor:"CameraErrorInternal" into:localizedErrorCStrs[CameraErrorInternal]];
  149.     [[self class] localizedCStrFor:"UnknownError" into:localizedUnknownErrorCStr];
  150.     return self;
  151. }
  152.  
  153. - (void) dealloc 
  154. {
  155.     [self shutdown];    //Make sure everything's shut down
  156.     if (cameraTypes!=NULL) 
  157.         [cameraTypes release]; 
  158.     cameraTypes=NULL;
  159.     
  160.     if (cameras!=NULL) 
  161.         [cameras release]; 
  162.     cameras=NULL;
  163.     
  164.     [super dealloc]; // where is the constructor?
  165. }
  166.  
  167. - (BOOL) startupWithNotificationsOnMainThread:(BOOL)nomt recognizeLaterPlugins:(BOOL)rlp{
  168.     MyCameraInfo*         info=NULL;
  169.     long             i;
  170.     long             numTestCameras=0;
  171.     id                 obj=NULL;
  172.     mach_port_t         masterPort;
  173.     CFMutableDictionaryRef     matchingDict;
  174.     CFRunLoopSourceRef        runLoopSource;
  175.     CFNumberRef            numberRef;
  176.     kern_return_t        ret;
  177.     SInt32            usbVendor;
  178.     SInt32            usbProduct;
  179.     io_iterator_t        iterator;
  180.     
  181.     NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
  182.     assert(cameraTypes);
  183.     assert(cameras);
  184.  
  185.     doNotificationsOnMainThread=nomt;
  186.     recognizeLaterPlugins=rlp;
  187.     
  188.     //Add Driver classes (this is where we have to add new model classes!)
  189.     [self registerCameraDriver:[MySPCA500Driver class]];
  190.     [self registerCameraDriver:[MyAiptekPocketDV class]];
  191.     [self registerCameraDriver:[MyKiaraFamilyDriver class]];
  192.     [self registerCameraDriver:[MyKiaraFlippedDriver class]];
  193.     [self registerCameraDriver:[MyTimonFamilyDriver class]];
  194.     [self registerCameraDriver:[MyCPIACameraDriver class]];
  195.     [self registerCameraDriver:[MyQX3Driver class]];
  196.     [self registerCameraDriver:[MyQX5Driver class]];
  197.     [self registerCameraDriver:[MySTV680Driver class]];
  198.     [self registerCameraDriver:[MyQCExpressADriver class]];
  199.     [self registerCameraDriver:[MyQCExpressBDriver class]];
  200.     [self registerCameraDriver:[MyQCWebDriver class]];
  201.     [self registerCameraDriver:[MyVicamDriver class]];
  202.     [self registerCameraDriver:[MySPCA504Driver class]];
  203.     [self registerCameraDriver:[MyOV511Driver class]];
  204.     [self registerCameraDriver:[MyOV511PlusDriver class]];
  205.     [self registerCameraDriver:[MySonix2028Driver class]];
  206.     [self registerCameraDriver:[MyViviCam3350BDriver class]];
  207.     [self registerCameraDriver:[MySwedaSSP09BDriver class]];
  208.     [self registerCameraDriver:[MySE401Driver class]];
  209.     [self registerCameraDriver:[MyQCProBeigeDriver class]];
  210.     [self registerCameraDriver:[MyQCVCDriver class]];
  211.     [self registerCameraDriver:[MyQCOrbitDriver class]];
  212.     [self registerCameraDriver:[SQ905 class]];
  213. //    [self registerCameraDriver:[MyIntelPCCameraPro class]];
  214. //    [self registerCameraDriver:[MyIntelPCCamera class]];
  215. //    [self registerCameraDriver:[MyGrandtecVcap class]];
  216. //    [self registerCameraDriver:[MyViewQuestM318B class]];
  217. //    [self registerCameraDriver:[MyViewQuestVQ110 class]];
  218. //    [self registerCameraDriver:[MyDVC325 class]];
  219.  
  220.     //Get the IOKit master port (needed for communication with IOKit)
  221.     ret = IOMasterPort(MACH_PORT_NULL, &masterPort);
  222.     if (ret||(!masterPort)) { NSLog(@"MyCameraCentral: IOMasterPort failed (%08x)", ret); return NO;}
  223.  
  224.     //Get a notification port, get its event source and connect it to the current thread
  225.     notifyPort = IONotificationPortCreate(masterPort);
  226.     runLoopSource = IONotificationPortGetRunLoopSource(notifyPort);
  227.     CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
  228.  
  229.     //Go through all our drivers and add plug-in notifications for them
  230.     for (i=0;i<[cameraTypes count];i++) {
  231.  
  232.         //Get info about the current camera
  233.         info=[cameraTypes objectAtIndex:i];
  234.         if (info==NULL) { NSLog(@"MyCameraCentral:wiringThread: bad info"); return NO; }
  235.         usbVendor =[info vendorID];
  236.         usbProduct=[info productID];
  237.  
  238.         // Set up the matching criteria for the devices we're interested in
  239.         matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
  240.         if (!matchingDict) { NSLog(@"MyCameraCentral:IOServiceMatching failed"); return NO; }
  241.  
  242.         // Add our vendor and product IDs to the matching criteria
  243.         numberRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&usbVendor);
  244.         CFDictionarySetValue(matchingDict,CFSTR(kUSBVendorID),numberRef);
  245.         CFRelease(numberRef); numberRef=NULL;
  246.  
  247.         numberRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&usbProduct);
  248.         CFDictionarySetValue(matchingDict,CFSTR(kUSBProductID),numberRef);
  249.         CFRelease(numberRef); numberRef=NULL;
  250.  
  251.         if (recognizeLaterPlugins) {
  252.             //Request notification if matching devices are plugged in or...
  253.             ret = IOServiceAddMatchingNotification(notifyPort,
  254.                                                    kIOFirstMatchNotification,
  255.                                                    matchingDict,
  256.                                                    DeviceAdded,
  257.                                                    info,
  258.                                                    &iterator);
  259.         } else {
  260.             //... just get the currently connected devices
  261.             ret = IOServiceGetMatchingServices(masterPort,
  262.                                                matchingDict,
  263.                                                &iterator);
  264.             
  265.         }
  266.         if (ret==0) {
  267.             //Get first devices and trigger notification process
  268.             DeviceAdded(info, iterator);
  269.  
  270.             //If we don't later notifications, we can release the enumerator
  271.             if (!recognizeLaterPlugins) {
  272.                 IOObjectRelease(iterator);
  273.             }
  274.         }
  275.     }
  276.     //Try to find out how many test cameras we have
  277.     obj=[self prefsForKey:@"Dummy cameras"];
  278.     if (obj) numTestCameras=[obj longValue];
  279.     else numTestCameras=0;
  280.  
  281.     //Add the dummy test image cameras to the list of available cameras
  282.     for (i=0;i<numTestCameras;i++) {
  283.         info=[[MyCameraInfo alloc] init];
  284.         [info setDriverClass:[MyDummyCameraDriver class]];
  285.         [info setProductID:[MyDummyCameraDriver cameraUsbProductID]];
  286.         [info setVendorID:[MyDummyCameraDriver cameraUsbVendorID]];
  287.         [info setCameraName: [NSString stringWithFormat:@"%@ #%i", [MyDummyCameraDriver cameraName], i+1]];
  288.         [info setCentral: self];
  289.         [cameras addObject:info];
  290.     }
  291.     
  292.     [pool release];
  293.     return YES;
  294. }
  295.  
  296. - (void) shutdown {
  297.     MyCameraInfo* info;
  298.     NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];    //Get a pool to catch the remaining drivers
  299.  
  300.     //shutdown all cameras
  301.     while ([cameras count]>0) {
  302.         info=[cameras lastObject];
  303.         [cameras removeLastObject];
  304.         //disconnect from the driver and autorelease our retain
  305.         if ([info driver]!=NULL) {
  306.             [[info driver] setCentral:NULL];
  307.             [[info driver] shutdown];
  308.         }
  309.         [info release];
  310.     }
  311.     //This would be a great place to release all USB notifications *****
  312.  
  313.     //release cameryTypes cameraInfos
  314.     while ([cameraTypes count]>0) {
  315.         info=[cameraTypes lastObject];
  316.         [cameraTypes removeLastObject];
  317.         [info release];
  318.     }
  319.     [pool release];
  320. }
  321.  
  322. - (id) delegate {
  323.     return delegate;
  324. }
  325.  
  326. - (void) setDelegate:(id)d {
  327.     delegate=d;
  328. }
  329.  
  330. - (BOOL) doNotificationsOnMainThread {
  331.     return doNotificationsOnMainThread;
  332. }
  333.  
  334. - (short) numCameras {
  335.     return [cameras count];
  336. }
  337.  
  338. - (short) indexOfCamera:(MyCameraDriver*)driver {
  339.     short i=0;
  340.     while (i<[cameras count]) {
  341.         if ([[cameras objectAtIndex:i] driver]==driver) return i;
  342.         else i++;
  343.     }
  344.     return -1;
  345. }
  346.  
  347. - (unsigned long) idOfCameraWithIndex:(short)idx {
  348.     if ((idx<0)||(idx>=[self numCameras])) return 0;
  349.     return [[cameras objectAtIndex:idx] cid];
  350. }
  351.  
  352. - (unsigned long) idOfCameraWithLocationID:(UInt32)locID {
  353.     short i;
  354.     for (i=0;i<[cameras count];i++) {
  355.         if ([[cameras objectAtIndex:i] locationID]==locID) return [[cameras objectAtIndex:i] cid];
  356.     }
  357.     return 0;    
  358. }
  359.  
  360. - (CameraError) useCameraWithID:(unsigned long)cid to:(MyCameraDriver**)outCam acceptDummy:(BOOL)acceptDummy {
  361.     long l;
  362.     MyCameraInfo* dev=NULL;
  363.     MyCameraDriver* cam=NULL;
  364.     CameraError err=CameraErrorOK;
  365.     if (outCam) *outCam=NULL;
  366.     for (l=0;(l<[cameras count])&&(dev==NULL);l++) {
  367.         dev=[cameras objectAtIndex:l];
  368.         if ([dev cid]!=cid) dev=NULL;
  369.     }
  370.     if (dev==NULL) {
  371. #ifdef VERBOSE
  372.         NSLog(@"MyCameraCentral: cid not found");
  373. #endif
  374.         err=CameraErrorInternal;
  375.     }
  376.     if (!err) {
  377.         if ([dev driver]) err=CameraErrorBusy;
  378.     }
  379.     if (!err) {
  380.         cam=[[[dev driverClass] alloc] initWithCentral:self];
  381.         if (!cam) {
  382. #ifdef VERBOSE
  383.             NSLog(@"MyCameraCentral: could not instantiate driver");
  384. #endif
  385.             err=CameraErrorNoMem;
  386.         }
  387.     }
  388.     if (!err) {
  389.         [cam setDelegate:delegate];
  390.         err=[cam startupWithUsbLocationId:[dev locationID]];
  391.         if (err!=CameraErrorOK) {
  392.             [cam release];
  393.             cam=NULL;
  394.         }
  395.     }
  396.     if (err&&acceptDummy) {    //We have an error and the sender wants a dummy in case of an error
  397.         cam=[self useDummyForError:err];
  398.     }
  399.     if (cam!=NULL) {
  400.         [dev setDriver:cam];
  401.         [cam setCameraInfo:dev];
  402.         [self setCameraToDefaults:cam];
  403.         if (outCam) *outCam=cam;
  404.     }
  405.     return err;
  406. }
  407.  
  408. - (MyCameraDriver*) useDummyForError:(CameraError)err {
  409.     MyCameraDriver* driver=[[MyDummyCameraDriver alloc] initWithError:err central:self];
  410.     if (driver) {
  411.         [driver setDelegate:delegate];
  412.         [driver startupWithUsbLocationId:0];
  413.     }
  414.     return driver;
  415. }
  416.  
  417. - (NSString*) nameForID:(unsigned long)cid {
  418.     long l=0;
  419.     while (l<[cameras count]) {
  420.         if ([[cameras objectAtIndex:l] cid]==cid) {
  421.             return [[cameras objectAtIndex:l] cameraName];
  422.         } else {
  423.             l++;
  424.         }
  425.     }
  426.     return NULL;
  427. }
  428.  
  429. - (NSString*) nameForDriver:(MyCameraDriver*)driver {
  430.     long l=0;
  431.     while (l<[cameras count]) {
  432.         if ([[cameras objectAtIndex:l] driver]==driver) {
  433.             return [[cameras objectAtIndex:l] cameraName];
  434.         } else l++;
  435.     }
  436.     return NULL;
  437. }
  438.  
  439. - (BOOL) getName:(char*)name forID:(unsigned long)cid {
  440.     NSString* camName=[self nameForID:cid];
  441.     if (!camName) return NO;
  442.     [camName getCString:name];
  443.     return YES;
  444. }
  445.  
  446. - (BOOL) getName:(char*)name forDriver:(MyCameraDriver*)driver {
  447.     NSString* camName=[self nameForDriver:driver];
  448.     if (!camName) return NO;
  449.     [camName getCString:name];
  450.     return YES;
  451. }
  452.  
  453. /*These functions read and write the camera settings. We cannot use the direct user defaults mechanism because we're sometimes a client in another app and we don't want to mess up the app's preferences. So we use the lower-level persistentDomainForName mechanism. */
  454.  
  455. - (BOOL) setCameraToDefaults:(MyCameraDriver*) cam {
  456.     NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
  457.     BOOL ok=YES;
  458.     short idx;
  459.     unsigned long cid;
  460.     NSDictionary* camDict;
  461.     if (ok) {
  462.         if (!cam) ok=NO;
  463.     }
  464.     if (ok) {
  465.         idx=[self indexOfCamera:cam];
  466.         if (idx<0) ok=NO;        //This camera is not listed as connected
  467.     }
  468.     if (ok) {
  469.         cid=[self idOfCameraWithIndex:idx];
  470.         if (cid<1) ok=NO;        //This camera has no cid (should not happen ever)
  471.     }
  472.     if (ok) {
  473.         //We use the driver class instead of the camera name to prevent differences due to localization
  474.         camDict=[self prefsForKey:NSStringFromClass([[cameras objectAtIndex:idx] driverClass])];
  475.         if (!camDict) ok=NO;        //There are no defaults for the camera listed
  476.     }
  477.     if (ok) {
  478.         if ([camDict objectForKey:@"brightness"])
  479.             [cam setBrightness:[[camDict objectForKey:@"brightness"] floatValue]];
  480.         if ([camDict objectForKey:@"contrast"])
  481.             [cam setContrast:[[camDict objectForKey:@"contrast"] floatValue]];
  482.         if ([camDict objectForKey:@"saturation"])
  483.             [cam setSaturation:[[camDict objectForKey:@"saturation"] floatValue]];
  484.         if ([camDict objectForKey:@"gamma"])
  485.             [cam setGamma:[[camDict objectForKey:@"gamma"] floatValue]];
  486.         if ([camDict objectForKey:@"sharpness"])
  487.             [cam setSharpness:[[camDict objectForKey:@"sharpness"] floatValue]];
  488.         if ([camDict objectForKey:@"gain"])
  489.             [cam setGain:[[camDict objectForKey:@"gain"] floatValue]];
  490.         if ([camDict objectForKey:@"shutter"])
  491.             [cam setShutter:[[camDict objectForKey:@"shutter"] floatValue]];
  492.         if ([camDict objectForKey:@"autogain"])
  493.             [cam setAutoGain:[[camDict objectForKey:@"autogain"] boolValue]];
  494.         if ([camDict objectForKey:@"hflip"])
  495.             [cam setHFlip:[[camDict objectForKey:@"hflip"] boolValue]];
  496.         if ([camDict objectForKey:@"compression"])
  497.             [cam setCompression:[[camDict objectForKey:@"compression"] shortValue]];
  498.         if ([camDict objectForKey:@"resolution"]&&[camDict objectForKey:@"fps"])
  499.             [cam setResolution:[[camDict objectForKey:@"resolution"] shortValue] fps:[[camDict objectForKey:@"fps"] shortValue]];
  500.            if ([camDict objectForKey:@"white balance"])
  501.             [cam setWhiteBalanceMode:(WhiteBalanceMode)[[camDict objectForKey:@"white balance"] shortValue]];
  502.     }
  503.     [pool release];
  504.     return ok;
  505. }
  506.  
  507. - (BOOL) saveCameraSettingsAsDefaults:(MyCameraDriver*) cam {
  508.     NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
  509.     BOOL ok=YES;
  510.     short idx;
  511.     unsigned long cid;
  512.     NSMutableDictionary* camDict;
  513.     if (ok) {
  514.         if (!cam) ok=NO;
  515.     }
  516.     if (ok) {
  517.         idx=[self indexOfCamera:cam];
  518.         if (idx<0) ok=NO;        //This camera is not listed as connected
  519.     }
  520.     if (ok) {
  521.         cid=[self idOfCameraWithIndex:idx];
  522.         if (cid<1) ok=NO;        //This camera has no cid (should not happen ever)
  523.     }
  524.     if (ok) {
  525.         camDict=[NSMutableDictionary dictionaryWithCapacity:11];
  526.         if (!camDict) ok=NO;
  527.     }
  528.     if (ok) {
  529.         if ([cam canSetBrightness])
  530.             [camDict setObject:[NSNumber numberWithFloat:[cam brightness]] forKey:@"brightness"];
  531.         if ([cam canSetContrast])
  532.             [camDict setObject:[NSNumber numberWithFloat:[cam contrast]] forKey:@"contrast"];
  533.         if ([cam canSetSaturation])
  534.             [camDict setObject:[NSNumber numberWithFloat:[cam saturation]] forKey:@"saturation"];
  535.         if ([cam canSetGamma])
  536.             [camDict setObject:[NSNumber numberWithFloat:[cam gamma]] forKey:@"gamma"];
  537.         if ([cam canSetSharpness])
  538.             [camDict setObject:[NSNumber numberWithFloat:[cam sharpness]] forKey:@"sharpness"];
  539.         if ([cam canSetGain])
  540.             [camDict setObject:[NSNumber numberWithFloat:[cam gain]] forKey:@"gain"];
  541.         if ([cam canSetShutter])
  542.             [camDict setObject:[NSNumber numberWithFloat:[cam shutter]] forKey:@"shutter"];
  543.         if ([cam canSetAutoGain])
  544.             [camDict setObject:[NSNumber numberWithBool:[cam isAutoGain]] forKey:@"autogain"];
  545.         if ([cam canSetHFlip])
  546.             [camDict setObject:[NSNumber numberWithBool:[cam hFlip]] forKey:@"hflip"];
  547.         if ([cam maxCompression]>0)
  548.             [camDict setObject:[NSNumber numberWithShort:[cam compression]] forKey:@"compression"];
  549.         if ([cam canSetWhiteBalanceMode])
  550.             [camDict setObject:[NSNumber numberWithShort:(short)[cam whiteBalanceMode]] forKey:@"white balance"];
  551.         
  552.         [camDict setObject:[NSNumber numberWithShort:[cam resolution]] forKey:@"resolution"];
  553.         [camDict setObject:[NSNumber numberWithShort:[cam fps]] forKey:@"fps"];
  554.         //We use the driver class instead of the camera name to prevent differences due to localization
  555.         [self setPrefs:camDict forKey:NSStringFromClass([[cameras objectAtIndex:idx] driverClass])];
  556.     }
  557.     [pool release];
  558.     return ok;
  559. }
  560.  
  561. void DeviceRemoved( void *refCon,io_service_t service,natural_t messageType,void *messageArgument ) {
  562.     MyCameraInfo* dev=(MyCameraInfo*)refCon;
  563.     if (messageType!=kIOMessageServiceIsTerminated) return;
  564.     if (dev==NULL) {
  565. #ifdef VERBOSE
  566.         NSLog(@"MaCameraCentral:DeviceRemoved: bad refCon");
  567. #endif
  568.     } else {
  569.         if ([dev driver]) [[dev driver] stopUsingUSB];    //Pass the info to the driver as fast as possible
  570.         [[dev central] deviceRemoved:[dev cid]];
  571.     }
  572. }
  573.     
  574. - (void) deviceRemoved:(unsigned long)cid {
  575.     kern_return_t    ret;
  576.     long l;
  577.     MyCameraInfo* dev=NULL;
  578.  
  579.     //remove the device in the cameras list
  580.     for (l=0;l<[cameras count];l++) {
  581.         if ([[cameras objectAtIndex:l] cid]==cid) {
  582.             dev=[cameras objectAtIndex:l];
  583.             [cameras removeObjectAtIndex:l];
  584.         }
  585.     }
  586.     if (!dev) {
  587. #ifdef VERBOSE
  588.         NSLog(@"MyCameraInfo:deviceRemoved: Tried to unregister a device not registered");
  589. #endif
  590.         return;    //We didn't find the camera
  591.     }
  592.     //Release the usb stuff
  593.     ret = IOObjectRelease([dev notification]);        //we don't need the usb notification any more
  594. //Initiate the driver shutdown.
  595.     if ([dev driver]!=NULL) {
  596.         [[dev driver] shutdown];    //We don't release it here - it is done in the cameraHasShutDown notification
  597.         [dev release];            //we still own it since we did not autorelease in [cameraAdded]
  598.     }
  599. }
  600.  
  601. void DeviceAdded(void *refCon, io_iterator_t iterator) {
  602.     MyCameraInfo* info=(MyCameraInfo*)refCon;
  603.     if (info!=NULL) {
  604.         [[info central] deviceAdded:iterator info:info];
  605.     }
  606. }
  607.  
  608. - (void) deviceAdded:(io_iterator_t)iterator info:(MyCameraInfo*)type {
  609.     kern_return_t    ret;
  610.     io_service_t    usbDeviceRef;
  611.     MyCameraInfo*    dev;
  612.     io_object_t        notification;
  613.     while (usbDeviceRef = IOIteratorNext(iterator)) {
  614.         UInt32 locID;
  615.         
  616.         //Setup our data object we use to track the device while it is plugged
  617.         dev=[type copy];
  618.         if (!dev) {
  619. #ifdef VERBOSE
  620.             NSLog(@"Could not copy MyCameraInfo object on insertion of a device");
  621. #endif
  622.             continue;
  623.         }
  624.  
  625.         //Request notification if the device is unplugged
  626.         ret = IOServiceAddInterestNotification(notifyPort,
  627.                                                usbDeviceRef,
  628.                                                kIOGeneralInterest,
  629.                                                DeviceRemoved,
  630.                                                dev,
  631.                                                ¬ification);
  632.         if (ret!=KERN_SUCCESS) {
  633. #ifdef VERBOSE
  634.             NSLog(@"IOServiceAddInterestNotification returned %08x\n",ret);
  635. #endif
  636.             [dev release];
  637.             continue;
  638.         }
  639.         //Try to find our USB location ID
  640.         if ([self locationIdOfUSBDeviceRef:usbDeviceRef to:&locID]!=CameraErrorOK) {
  641. #ifdef VERBOSE
  642.             NSLog(@"failed to get location id");
  643. #endif
  644.             [dev release];
  645.             continue;
  646.         }
  647.         //Remember the notification (we have to release it later)
  648.         [dev setNotification:notification];
  649.         [dev setLocationID:locID];
  650.  
  651.         //Put the new entry to the list of available cameras
  652.         [cameras addObject:dev];
  653.  
  654.         //Spread the news that a camera was plugged in
  655.         [self cameraDetected:[dev cid]];
  656.     }
  657. }
  658.  
  659. - (void) cameraDetected:(unsigned long) cid {
  660.     if (delegate) {
  661.         if ([delegate respondsToSelector:@selector(cameraDetected:)]) {
  662.             [delegate cameraDetected:cid];
  663.         }
  664.     }
  665. }
  666.  
  667. - (void) cameraHasShutDown:(id)sender {
  668.     long i;
  669.     MyCameraInfo* info;
  670.     for(i=0;i<[cameras count];i++) {
  671.         info=[cameras objectAtIndex:i];
  672.         if ([info driver]==sender) {
  673.             [info setDriver:NULL];    //If it's still in the list: mark it as available
  674.         }
  675.     }
  676.     [sender autorelease];        //We clear our reference to that driver. When we receive this, we have built it.
  677. }
  678.  
  679.  
  680.  
  681. - (id) prefsForKey:(NSString*) key {
  682.     id val=NULL;
  683.     if (!key) return NULL;        //No key, no value
  684.     if (!prefsDict) {            //No prefs there. Try to load prefs file.
  685.         NSString* pathName=[[NSString stringWithFormat:@"~/Library/Preferences/%@.plist",driverBundleName] stringByExpandingTildeInPath];
  686.         NSDictionary* dict;
  687.         dict=[NSDictionary dictionaryWithContentsOfFile:pathName];
  688.         if (dict) prefsDict=[dict mutableCopy];
  689.     }
  690.     if (!prefsDict) {            //No file there. Try to open a new one
  691.         prefsDict=[[NSMutableDictionary alloc] initWithCapacity:3];
  692.     }
  693.     if (!prefsDict) return NULL;    //Still no prefs dict there - give up
  694.     val=[prefsDict objectForKey:key];
  695.     if (!val) return NULL;        //No value for that key
  696.     val=[val copy];
  697.     if (!val) return NULL;        //Probably no mem or some non-copying object (could that happen? I guess not)
  698.     [val autorelease];
  699.     return val;
  700. }
  701.  
  702. - (void) setPrefs:(id)value forKey:(NSString*)key {
  703.     NSString* pathName;
  704.     if (!key) return;            //No key, no change
  705.     [self prefsForKey:key];        //Ensure the prefs are loaded
  706.     if (!prefsDict) return;        //Still no prefs? Give up.
  707. //Do the change
  708.     if (value) {
  709.         [prefsDict setObject:[[value copy] autorelease] forKey:key];
  710.     } else {
  711.         [prefsDict removeObjectForKey:key];
  712.     }
  713. //Write to file
  714.     pathName=[[NSString stringWithFormat:@"~/Library/Preferences/%@.plist",driverBundleName] stringByExpandingTildeInPath];
  715.     [prefsDict writeToFile:pathName atomically:YES];
  716. }
  717.  
  718. - (void) registerCameraDriver:(Class)driver {
  719.     NSArray* arr=[driver cameraUsbDescriptions];
  720.     int i;
  721.     for (i=0;i<[arr count];i++) {
  722.         NSDictionary* dict=[arr objectAtIndex:i];
  723.         MyCameraInfo* info=[[MyCameraInfo alloc] init];
  724.         if (info!=NULL) {
  725.             [info setCameraName:[dict objectForKey:@"name"]];
  726.             [info setVendorID:[[dict objectForKey:@"idVendor"] unsignedShortValue]];
  727.             [info setProductID:[[dict objectForKey:@"idProduct"] unsignedShortValue]];
  728.             [info setDriverClass:driver];
  729.             [info setCentral: self];
  730.             [cameraTypes addObject:info];
  731.         }
  732.     }
  733. }
  734.  
  735. - (CameraError) locationIdOfUSBDeviceRef:(io_service_t)usbDeviceRef to:(UInt32*)outVal {
  736.     UInt32 locID=0;
  737.     kern_return_t kernelErr;
  738.     SInt32 score;
  739.     IOCFPlugInInterface **plugin=NULL;
  740.     CameraError err=CameraErrorOK;
  741.     HRESULT res;
  742.     IOUSBDeviceInterface** dev=NULL;
  743.  
  744.     kernelErr = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
  745.  
  746.     if ((kernelErr!=kIOReturnSuccess)||(!plugin)) {
  747. #ifdef VERBOSE
  748.         NSLog(@"MyCameraCentral: IOCreatePlugInInterfaceForService; Could not get plugin");
  749. #endif
  750.         return CameraErrorUSBProblem;
  751.     }
  752.     if (!err) {
  753.         res=(*plugin)->QueryInterface(plugin,CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),(LPVOID*)(&dev));
  754.         (*plugin)->Release(plugin);
  755.         plugin=NULL;
  756.         if ((res)||(!dev)) {
  757. #ifdef VERBOSE
  758.             NSLog(@"MyCameraCentral: IOCreatePlugInInterfaceForService; Could not get device interface");
  759. #endif
  760.             err=CameraErrorUSBProblem;
  761.         }
  762.     }
  763.     if (!err) {
  764.         kernelErr = (*dev)->GetLocationID(dev,&locID);
  765.         (*dev)->Release(dev);
  766.         if (kernelErr!=KERN_SUCCESS) {
  767. #ifdef VERBOSE
  768.             NSLog(@"MyCameraCentral: IOCreatePlugInInterfaceForService; Could not get Location ID");
  769. #endif
  770.             err=CameraErrorUSBProblem;
  771.         }
  772.     }
  773.     if (outVal) {
  774.         if (!err) *outVal=locID;
  775.         else *outVal=0;
  776.     }
  777.     return err;
  778. }
  779.  
  780.  
  781.     
  782.     
  783.  
  784. @end
  785.