#include typedef struct IsochComponentInstance IsochComponentInstance, *IsochComponentInstancePtr; typedef struct IsochComponentGlobals IsochComponentGlobals, *IsochComponentGlobalsPtr; #define CALLCOMPONENT_BASENAME() IDHDV #define CALLCOMPONENT_GLOBALS() IsochComponentInstancePtr storage #define IDH_BASENAME() FWDV #define IDH_GLOBALS() IsochComponentInstancePtr storage #include "IsochronousDataHandler.k.h" #include "DeviceControlPriv.h" #include "DVVers.h" #include #include #include // usleep() #include #include // Debug messages // Timebase stuff #include #include // Trace stuff #include #include #include #include #include #include #include #define kDVRequestID 0 #define kIOPending 1 #define kIORunning 2 #define kMaxDeviceClients 4 #define DEBUG 0 //#define DRAWRINGBUFFERGRAPH /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define kDVDeviceInfo 'ddin' // DV device info #define kMaxDevicesActive 64 // max devices on firewire bus #define kMaxInstances 10 // max clients attached to a device #define kMaxNotifications 100 // 100 notifications can be supported #define kNTSCCompressedBufferSize 120000 #define kPALCompressedBufferSize 144000 #define kIDHSeedAtomType 'seed' // seed for device atom validity #define kIDHDevicePresentType 'pres' // is device present? #define kServiceTypeDVServices 'avc ' #define kTimeoutDuration (1000 / 15) * durationMillisecond // 1/15 second (2 frame times) typedef struct ClientNotification { ComponentInstance ihc; IDHDeviceID deviceID; IDHNotificationProc notificationProc; IDHEvent events; void *userData; } ClientNotification; // describes a device on the firewire bus typedef struct DeviceDescription { UInt64 fGUID; // persistent unique ID for each device io_object_t fID; // IOKit ID for each device io_connect_t fConnection; io_object_t fNotification; // Handle for messages from kernel driver IsochComponentGlobalsPtr fGlobals; UInt32 fNumOutputFrames; vm_address_t *bufMem; // Buffers shared with kernel driver IOFWDVSharedVars *fSharedVars; // Structure shared with kernel driver vm_address_t fDCLBuffer; // DCL Buffers shared with kernel driver IOFWDVWriteSharedData *fSharedWriteVars; // For access to output DCL variables UInt32 * fOldWriteTimeStamps; int fDCLReadPos; // Which block the DCL write program will process next int fBufWritePos; // Next block to write data into int fFrameBufferPos; // Current offset into current frame buffer int fDCLSavedPacketNum; // Current packet in DCL buffer when we're waiting for a frame UInt8 * fDCLSavedWritePos; // Current position in DCL buffer when we're waiting for the next frame int fBufSize; // NTSC or PAL frame int fOldDrop; // Dropped before int fOldRead; // Where DV driver was before IsochComponentInstancePtr fOpenClients[kMaxDeviceClients]; // component instances doing I/O to/from device int fBufferLocks[kDVNumOutputFrames]; ComponentInstance deviceControlInstance; // device control component instance Component clock; // FireWire clock component, clients get their own instance, not sure why UInt32 standard; // device standard QTAtomContainer deviceContainer; // contains device database SInt16 deviceControlCount; // number of clients using device control SInt16 readLocks; // num clients that have device open for reads SInt16 writeLocks; // num clients that have device open for writes Boolean active; // device is currently online Boolean fHasSDL; // true if device can do SDL (half data rate) UInt8 fOutputMode; // AVC output signal mode - NTSC/SDL etc. Boolean fWaitingStartWrite; // True if we're filling up buffers before starting to write Boolean fConnected; // device is currently configured #ifdef DRAWRINGBUFFERGRAPH Ptr fScreenBaseAddr; UInt32 fPixDepth; UInt32 fRowBytes; #endif } DeviceDescription, *DeviceDescriptionPtr; #ifdef DRAWRINGBUFFERGRAPH static void SetUpBlitGlobals(DeviceDescriptionPtr ddp); static void BlitBufferGraph(DeviceDescriptionPtr ddp); #endif struct IsochComponentGlobals { // Globals UInt32 useCMP; // CMP off by default, turn on by adding 'ucmp' resource DeviceDescription deviceDescription[kMaxDevicesActive]; // description of each device ClientNotification clientNotification[kMaxNotifications]; // arbirtary # of notifications UInt32 nDevices; // number of devices in the list UInt32 seed; // keep track of device lists // X Stuff mach_port_t fMasterDevicePort; // Master port for IOKit IONotificationPortRef fNotifyPort; // Our IOKit notification port mach_port_t fNotifyMachPort; // notify port as a mach port io_iterator_t fMatchEnumer; // Iterator over matching devices pthread_t fWorkThread; // For notifications and I/O pthread_attr_t fThreadAttr; // Attributes of work thread pthread_mutex_t fGlobalsMutex; // lock this before updating globals pthread_cond_t fSyncCond; // To synchronize threads. UInt32 fGlobalsState; // 0 = uninitted. CFBundleRef fBundleID; // Of the DV component's bundle int fNumInstances; }; struct IsochComponentInstance { // Instance variables ComponentInstance self; QTAtomSpec currentConfig; // current device config set by client IDHDeviceID deviceID; // current deviceID UInt16 fClientIndex; // into device client list long permissions; // open permissions IDHParameterBlock * fHead; // Of I/O queue IDHParameterBlock * fTail; // Of I/O queue IDHParameterBlock * fActiveHead; // Of I/Os referencing the ring buffer IDHParameterBlock * fActiveTail; // Of I/O referencing the ring buffer UInt32 fSyncRequest; // Flag to indicate completion of synchronous operation ComponentResult fSyncResult; // Result of sync operation Boolean hasDeviceControl; // does this client have device control? }; typedef struct { UInt32 fRequest; IsochComponentInstancePtr fInstance; void * fParams; } DVRequest; typedef struct { mach_msg_header_t msgHdr; DVRequest dvRequest; } SendMsg; typedef struct { mach_msg_header_t msgHdr; union { OSNotificationHeader notifyHeader; DVRequest dvRequest; UInt8 grr[72]; // Enough for IOServiceInterestContent }body; mach_msg_trailer_t trailer; } ReceiveMsg; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Function prototypes */ pascal ComponentResult FWDVICodecComponentDispatch(ComponentParameters *params, char ** storage); static pascal ComponentResult FWDVIDHCloseDevice(IsochComponentInstancePtr ih); /* Globals */ static IsochComponentGlobals globals; /* ---------------------- Debug Stuff -------------------------- */ #ifdef DEBUG #define FailMessage(cond) assert (!(cond)) #else #define FailMessage(cond) {} #endif #define FailWithVal(cond, handler,num) \ if (cond) { \ goto handler; \ } #define FailWithAction(cond, action, handler) \ if (cond) { \ { action; } \ goto handler; \ } #define FailIf(cond, handler) \ if (cond) { \ FailMessage(false); \ goto handler; \ } #if DEBUG static char * print4(UInt32 val, char *buf) { char a, b, c, d; a = val>>24; b = val>>16; c = val>>8; d = val; if(a >= ' ' && b >= ' ' && c >= ' ' && d >= ' ') //printf("%c%c%c%c", a, b, c, d); //syslog(LOG_INFO, "%c%c%c%c", a, b, c, d); sprintf(buf, "%c%c%c%c", a, b, c, d); else //printf(" 0x%x ", (int)val); //syslog(LOG_INFO, " 0x%x ", (int)val); sprintf(buf, " 0x%x ", (int)val); return buf + strlen(buf); } static void RecordEventLogger(UInt32 a, UInt32 b, UInt32 c, UInt32 d) { char buf[256]; char *curr = buf; sprintf(buf, "0x%x:", pthread_self()); curr = buf + strlen(buf); if(a) curr = print4(a, curr); if(b) curr = print4(b, curr); if(c) curr = print4(c, curr); if(d) curr = print4(d, curr); printf("%s\n", buf); syslog(LOG_INFO, buf); } #else #define RecordEventLogger(a, b, c, d) #endif //masks for SYS_kdebug_trace code #define kKernelTraceEnable (1 << 0 ) #define kKernelTraceDisable (1 << 1 ) #define kIOFWDVTrace 0x08001000 static int pKGSysCall_Start (int code, int param1, int param2, int param3, int param4, int param5, int param6 ) { return syscall ( SYS_kdebug_trace, code | kKernelTraceEnable, param1, param2, param3, param4, param5, param6 ); } static int pKGSysCall_End (int code, int param1, int param2, int param3, int param4, int param5, int param6 ) { return syscall ( SYS_kdebug_trace, code | kKernelTraceDisable, param1, param2, param3, param4, param5, param6 ); } static int pKGSysCall_Insert (int code, int param1, int param2, int param3, int param4, int param5, int param6 ) { return syscall ( SYS_kdebug_trace, code , param1, param2, param3, param4, param5, param6 ); } static void dropMsg(DeviceDescription *deviceDescriptionPtr) { pKGSysCall_Insert (kIOFWDVTrace, 'drop', deviceDescriptionPtr->fSharedVars->fDroppedFrames- deviceDescriptionPtr->fOldDrop, deviceDescriptionPtr->fSharedVars->fDroppedFrames, 0, 0, 0); syslog(LOG_INFO,"Just dropped %ld frames (total %ld)!\n", deviceDescriptionPtr->fSharedVars->fDroppedFrames-deviceDescriptionPtr->fOldDrop, deviceDescriptionPtr->fSharedVars->fDroppedFrames); deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fSharedVars->fDroppedFrames; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void signalSync(UInt32 *var, UInt32 val) { pthread_mutex_lock(&globals.fGlobalsMutex); *var = val; pthread_mutex_unlock(&globals.fGlobalsMutex); pthread_cond_broadcast(&globals.fSyncCond); } static void waitSync(UInt32 *var) { if(!*var) { pthread_mutex_lock(&globals.fGlobalsMutex); while(!*var) { pthread_cond_wait(&globals.fSyncCond, &globals.fGlobalsMutex); } pthread_mutex_unlock(&globals.fGlobalsMutex); } } OSErr findDeviceDescriptionforDevice( IsochComponentInstancePtr ih, UInt32 deviceID, DeviceDescription **deviceDescription) { OSErr result = noErr; *deviceDescription = (DeviceDescriptionPtr)deviceID; return result; } //еее do a super find atom someday static OSErr findAtom( const QTAtomSpec *atomSpec, OSType theType, QTAtom *theAtom) { OSErr result = noErr; OSType type; QTAtom atom; atom = atomSpec->atom; result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil); FailWithVal( result != noErr, Exit, result); while( type != kIDHDeviceAtomType && type != theType) { atom = QTGetAtomParent( atomSpec->container, atom); // should be isoch atom FailWithAction( atom == nil || atom == -1, result = kIDHErrDeviceList, Exit); result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil); FailWithVal( result != noErr, Exit, result); } if( theType == type) { *theAtom = atom; result = noErr; } else { *theAtom = nil; result = kIDHErrDeviceList; } Exit: return result; } static OSErr getDeviceID( QTAtomSpec *configID, UInt32 *deviceID) { OSErr result = noErr; QTAtom deviceAtom; *deviceID = nil; result = findAtom( configID, kIDHDeviceAtomType, &deviceAtom); FailWithVal( result != noErr, Exit, result); result = QTGetAtomTypeAndID( configID->container, deviceAtom, nil, (long *) deviceID); FailWithVal( result != noErr, Exit, result); Exit: return result; } static OSErr closeDeviceControl( IsochComponentInstancePtr ih, DeviceDescriptionPtr deviceDescriptionPtr) { OSErr result = noErr; if( deviceDescriptionPtr->deviceControlInstance) { if( --deviceDescriptionPtr->deviceControlCount <= 0) { deviceDescriptionPtr->deviceControlCount = 0; result = DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance); result = DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance, kIDHInvalidDeviceID); CloseComponent(deviceDescriptionPtr->deviceControlInstance); deviceDescriptionPtr->deviceControlInstance = nil; } } return result; } OSErr checkSeed( IsochComponentGlobalsPtr gGlobals, QTAtomSpec *configID) { QTAtom seedAtom; OSErr result = noErr; UInt32 seed; // look for device in device container seedAtom = QTFindChildByIndex( configID->container, kParentAtomIsContainer, kIDHSeedAtomType, 1, nil); FailWithAction( seedAtom == nil, result = kIDHErrDeviceList, Exit); QTLockContainer( configID->container); // get the value of the devicePresent atom QTCopyAtomDataToPtr( configID->container, seedAtom, true, sizeof( seed), &seed, nil); QTUnlockContainer( configID->container); // seed has expired? if( seed != gGlobals->seed) { result = kIDHErrDeviceList; goto Exit; } Exit: return result; } static OSErr setupVideoAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard, Boolean isSDL) { OSErr result = noErr; QTAtom configAtom; OSType type; long size; float interval; long direction; IDHDimension dimension; IDHResolution resolution; Fixed refresh; OSType pixel; OSType decoType; Component decoComponent; ComponentDescription compDescrip; // create a vide NTSC mode result = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 0, 0, 0, nil, &configAtom); FailWithVal( result != noErr, Exit, result); type = kIDHVideoMediaAtomType; result = QTInsertChild( container, configAtom, kIDHIsochMediaType, 0, 0, sizeof( type), &type, nil); FailWithVal( result != noErr, Exit, result); if(isSDL) { result = QTInsertChild( container, configAtom, kIDHNameAtomType, 0, 0, 7, "\pDV-SDL", nil); } else { result = QTInsertChild( container, configAtom, kIDHNameAtomType, 0, 0, 3, "\pDV", nil); } FailWithVal( result != noErr, Exit, result); type = (standard == ntscIn)?'DVC ':'DVCP'; result = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 0, 0, sizeof( type), &type, nil); FailWithVal( result != noErr, Exit, result); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; if(isSDL) size /= 2; result = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( result != noErr, Exit, result); result = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( result != noErr, Exit, result); interval = 29.97; result = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 0, 0, sizeof( interval), &interval, nil); FailWithVal( result != noErr, Exit, result); direction = kIDHDataTypeIsInputAndOutput; result = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 0, 0, sizeof( direction), &direction, nil); FailWithVal( result != noErr, Exit, result); dimension.x = 720; dimension.y = (standard == ntscIn)?480:576; result = QTInsertChild( container, configAtom, kIDHVideoDimensionsAtomType, 0, 0, sizeof( dimension), &dimension, nil); FailWithVal( result != noErr, Exit, result); resolution.x = 72 << 16; resolution.y = 72 << 16; result = QTInsertChild( container, configAtom, kIDHVideoResolutionAtomType, 0, 0, sizeof( resolution), &resolution, nil); FailWithVal( result != noErr, Exit, result); refresh = (29 << 16) + 97; //еее result = QTInsertChild( container, configAtom, kIDHVideoRefreshRateAtomType, 0, 0, sizeof( refresh), &refresh, nil); FailWithVal( result != noErr, Exit, result); pixel = 'dv '; //еее result = QTInsertChild( container, configAtom, kIDHVideoPixelTypeAtomType, 0, 0, sizeof( pixel), &pixel, nil); FailWithVal( result != noErr, Exit, result); //еее kIDHVideoDecompressorsAtomType = FOUR_CHAR_CODE('deco'), decoType = (standard == ntscIn)?'dvc ':'dvcp'; result = QTInsertChild( container, configAtom, kIDHVideoDecompressorTypeAtomType, 0, 0, sizeof( decoType), &decoType, nil); FailWithVal( result != noErr, Exit, result); compDescrip.componentType = 'imdc'; compDescrip.componentSubType = decoType; compDescrip.componentManufacturer = 0; compDescrip.componentFlags = 0; compDescrip.componentFlagsMask = 0; decoComponent = FindNextComponent( nil, &compDescrip); result = QTInsertChild( container, configAtom, kIDHVideoDecompressorComponentAtomType, 0, 0, sizeof( decoComponent), &decoComponent, nil); FailWithVal( result != noErr, Exit, result); Exit: return result; } static OSErr setup48kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) { OSErr err; QTAtom configAtom; StringPtr name; OSType type; long size; Fixed rate; float interval; long direction; // create a vide NTSC mode err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 0, 0, 0, nil, &configAtom); FailWithVal( err != noErr, Exit, err); type = kIDHSoundMediaAtomType; err = QTInsertChild( container, configAtom, kIDHIsochMediaType, 0, 0, sizeof( type), &type, nil); FailWithVal( err != noErr, Exit, err); name = "\pDV-48khz"; err = QTInsertChild( container, configAtom, kIDHNameAtomType, 0, 0, name[0]+1, name, nil); FailWithVal( err != noErr, Exit, err); type = 'DV48'; err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 0, 0, sizeof( type), &type, nil); FailWithVal( err != noErr, Exit, err); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); interval = 29.97; err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 0, 0, sizeof( interval), &interval, nil); FailWithVal( err != noErr, Exit, err); direction = kIDHDataTypeIsInputAndOutput; err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 0, 0, sizeof( direction), &direction, nil); FailWithVal( err != noErr, Exit, err); size = 2; err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); size = 2; err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); rate = rate44khz; err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType, 0, 0, sizeof( rate), &rate, nil); FailWithVal( err != noErr, Exit, err); Exit: return err; } // sound 1 config static OSErr setup32kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) { OSErr err; QTAtom configAtom; StringPtr name; OSType type; long size; Fixed rate; float interval; long direction; // create a vide NTSC mode err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 0, 0, 0, nil, &configAtom); FailWithVal( err != noErr, Exit, err); type = kIDHSoundMediaAtomType; err = QTInsertChild( container, configAtom, kIDHIsochMediaType, 0, 0, sizeof( type), &type, nil); FailWithVal( err != noErr, Exit, err); name = "\pDV-32khz"; err = QTInsertChild( container, configAtom, kIDHNameAtomType, 0, 0, name[0]+1, name, nil); FailWithVal( err != noErr, Exit, err); type = 'DV32'; err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 0, 0, sizeof( type), &type, nil); FailWithVal( err != noErr, Exit, err); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); interval = 29.97; err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 0, 0, sizeof( interval), &interval, nil); FailWithVal( err != noErr, Exit, err); direction = kIDHDataTypeIsInputAndOutput; err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 0, 0, sizeof( direction), &direction, nil); FailWithVal( err != noErr, Exit, err); size = 4; err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); size = 2; err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); rate = 32000 << 16; err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType, 0, 0, sizeof( rate), &rate, nil); FailWithVal( err != noErr, Exit, err); Exit: return err; } // sound 2 config static OSErr setup44kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) { OSErr err; QTAtom configAtom; StringPtr name; OSType type; long size; Fixed rate; float interval; long direction; // create a vide NTSC mode err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 0, 0, 0, nil, &configAtom); FailWithVal( err != noErr, Exit, err); type = kIDHSoundMediaAtomType; err = QTInsertChild( container, configAtom, kIDHIsochMediaType, 0, 0, sizeof( type), &type, nil); FailWithVal( err != noErr, Exit, err); name = "\pDV-44khz"; err = QTInsertChild( container, configAtom, kIDHNameAtomType, 0, 0, name[0]+1, name, nil); FailWithVal( err != noErr, Exit, err); type = 'DV44'; err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 0, 0, sizeof( type), &type, nil); FailWithVal( err != noErr, Exit, err); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); interval = 29.97; err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 0, 0, sizeof( interval), &interval, nil); FailWithVal( err != noErr, Exit, err); direction = kIDHDataTypeIsInputAndOutput; err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 0, 0, sizeof( direction), &direction, nil); FailWithVal( err != noErr, Exit, err); size = 4; err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); size = 2; err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType, 0, 0, sizeof( size), &size, nil); FailWithVal( err != noErr, Exit, err); rate = 44100 << 16; err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType, 0, 0, sizeof( rate), &rate, nil); FailWithVal( err != noErr, Exit, err); Exit: return err; } // sound 3 config static OSStatus cameraNameLookup(DeviceDescriptionPtr pDeviceDescription, UInt8 *name) { CFDictionaryRef properties; CFStringRef dataDesc; OSStatus result; Boolean done; result = IORegistryEntryCreateCFProperties(pDeviceDescription->fID, &properties, kCFAllocatorDefault, kNilOptions); if(result != noErr) return result; dataDesc = (CFStringRef)CFDictionaryGetValue(properties, CFSTR("FireWire Product Name")); if(dataDesc) { done = CFStringGetPascalString(dataDesc, name, 255, kCFStringEncodingMacRoman); } else { // Look up vendor ID in resource list UInt32 vendorID = pDeviceDescription->fGUID >> 40; Handle h; UInt32 *pGuid; UInt32 guidCount; UInt32 i, index; Str255 cameraName = "\pDV"; // in case we don't find anything SInt16 refNum = -1, localizedRefNum = -1; BlockMoveData(cameraName, name, cameraName[0] + 1); // read vendor id resource and look for matching guid if(pDeviceDescription->fGlobals->fBundleID == 0) { CFBundleRef myRef; myRef = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.IOFWDVComponents")); CFBundleOpenBundleResourceFiles(myRef, &refNum, &localizedRefNum); pDeviceDescription->fGlobals->fBundleID = myRef; } h = Get1Resource('vnid', -20775); // jkl, get resource assignment and constant result = ResError(); if (h && (result == noErr)) { HLock(h); // first long is number of vendor id's stored in resource guidCount = **((UInt32 **) h); pGuid = *((UInt32 **) h); pGuid++; for (i = 0, index = 1; i < guidCount; i++, index++) { if (pGuid[i] == vendorID) { // found device, get its name GetIndString(cameraName, -20775, index); if (cameraName[0]) { BlockMoveData(cameraName, name, cameraName[0] + 1); BlockMoveData(" DV", name + name[0] + 1, 3); name[0] += 3; break; } } } HUnlock(h); ReleaseResource(h); } } CFRelease(properties); return result; } static OSErr postEvent(IsochComponentGlobalsPtr g, IDHDeviceID deviceID, IDHEvent event) { UInt32 i; IDHDeviceConnectionEvent connectionEvent; OSErr error = noErr; // We now have two broad classifications of events - ones that need to be // reported ASAP, which are stream related: // // kIDHPrivateEventReadComplete // kIDHPrivateEventWriteComplete // // and ones that are device management related, whose notifications will // probably generate massive amounts of task-level only Toolbox calls: // // kIDHEventDeviceAdded // kIDHEventDeviceRemoved // kIDHEventReadEnabled // kIDHEventReadDisabled // kIDHEventWriteEnabled // kIDHEventWriteDisabled // // kIDHPrivateEventReadComplete and kIDHPrivateEventWriteComplete are posted to a secondary // interrupt handler. All other events are handled immediately. RecordEventLogger( 'isoc', 'post', deviceID, event); for (i = 0; i < kMaxNotifications ; ++i) { ClientNotification* clientNotification = &g->clientNotification[i]; IDHDeviceID clientDeviceID = clientNotification->deviceID; IDHEvent wantedEvents = clientNotification->events; if (event & wantedEvents) { // Send notification if the device matches the client's desired device // or client specified all devices. if ((kIDHDeviceIDEveryDevice == clientDeviceID) || (deviceID == clientDeviceID) ) { // we currently only support a one-shot notification, like clock callbacks clientNotification->events = 0; switch(event) { case kIDHEventDeviceChanged: case kIDHEventDeviceAdded: case kIDHEventDeviceRemoved: case kIDHEventReadEnabled: case kIDHEventReadDisabled: case kIDHEventWriteEnabled: case kIDHEventWriteDisabled: connectionEvent.eventHeader.event = event; connectionEvent.eventHeader.deviceID = deviceID; connectionEvent.eventHeader.notificationID = (UInt32)clientNotification; (*clientNotification->notificationProc) ((IDHGenericEvent*)&connectionEvent, clientNotification->userData); break; default: RecordEventLogger( 'isoc', 'post', '????', event); break; } } } } RecordEventLogger( 'isoc', 'post', 'end ', event); return error; } static void deviceMessage(void * refcon, io_service_t service, natural_t messageType, void *messageArgument) { //syslog(LOG_INFO,"Got message: refcon %d, service 0x%x type 0x%x arg %p\n", // refcon, service, messageType, messageArgument); if(messageType == kIOMessageServiceIsTerminated) { DeviceDescriptionPtr deviceDescriptionPtr = (DeviceDescriptionPtr)refcon; if(deviceDescriptionPtr->deviceControlInstance) { DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance); DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance, kIDHInvalidDeviceID); } if(deviceDescriptionPtr->fConnection) { // Close the connection IOServiceClose(deviceDescriptionPtr->fConnection); deviceDescriptionPtr->fConnection = NULL; } if(deviceDescriptionPtr->fNotification) { IOObjectRelease(deviceDescriptionPtr->fNotification); deviceDescriptionPtr->fNotification = NULL; } if(deviceDescriptionPtr->fID) { IOObjectRelease(deviceDescriptionPtr->fID); deviceDescriptionPtr->fID = NULL; } // post a DV event to let the curious know... postEvent(deviceDescriptionPtr->fGlobals, (IDHDeviceID)deviceDescriptionPtr, kIDHEventDeviceRemoved); } } //==================================================================================== // // registerDevice() // Register the device and install the FireWire port callback routines and bus reset proc. // //==================================================================================== static OSStatus registerDevice(DeviceDescriptionPtr pDeviceDescription) { OSStatus err = noErr; return err; } static OSStatus findBuffers(DeviceDescription *deviceDescriptionPtr) { unsigned int size; int nFrames; vm_address_t *buffs; vm_size_t shmemSize; int i; OSStatus result = noErr; size = 0; nFrames = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVGetNumOutputFrames, NULL, 0, NULL, &size); if(nFrames < 0) return nFrames; // Probably an error code. buffs = (vm_address_t *)NewPtr(nFrames * sizeof(vm_address_t)); if(!buffs) return MemError(); for(i=0; ifConnection,i,mach_task_self(), &buffs[i],&shmemSize,kIOMapAnywhere); FailIf(result != noErr, Exit); // Try to make sure VM isn't confused. bzero((void *)buffs[i], shmemSize); } // Get status vars. result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,kDVNumOutputFrames+4,mach_task_self(), (vm_address_t *)&deviceDescriptionPtr->fSharedVars,&shmemSize,kIOMapAnywhere); //printf("res: 0x%x mapped vars to 0x%x: %d bytes\n", (int)result, // (int)deviceDescriptionPtr->fSharedVars, shmemSize); FailIf(result != noErr, Exit); deviceDescriptionPtr->fNumOutputFrames = nFrames; deviceDescriptionPtr->bufMem = buffs; deviceDescriptionPtr->fBufSize = (deviceDescriptionPtr->standard == ntscIn)? kNTSCCompressedBufferSize:kPALCompressedBufferSize; Exit: return result; } static OSStatus enableRead(DeviceDescription *deviceDescriptionPtr) { unsigned int size; OSStatus result; findBuffers(deviceDescriptionPtr); size = 0; result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVReadStart, NULL, 0, NULL, &size); if(result == noErr) { deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fSharedVars->fDroppedFrames; } return result; } static OSStatus disableRead(DeviceDescription *deviceDescriptionPtr) { unsigned int size; OSStatus result; size = 0; result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVReadStop, NULL, 0, NULL, &size); return result; } static OSStatus enableWrite(DeviceDescription *deviceDescriptionPtr) { unsigned int size; OSStatus result; vm_size_t shmemSize; int mode; findBuffers(deviceDescriptionPtr); size = 0; mode = deviceDescriptionPtr->fOutputMode; result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVSetWriteSignalMode, &mode, 1, NULL, &size); { int i; // Map the shared write data structure result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,kDVNumOutputFrames+5,mach_task_self(), (vm_address_t *)&deviceDescriptionPtr->fSharedWriteVars,&shmemSize,kIOMapAnywhere); FailIf(result != noErr, Exit); deviceDescriptionPtr->fOldWriteTimeStamps = (UInt32 *)NewPtr(deviceDescriptionPtr->fSharedWriteVars->fNumGroups*sizeof(UInt32)); for(i=0; ifSharedWriteVars->fNumGroups; i++) { deviceDescriptionPtr->fOldWriteTimeStamps[i] = deviceDescriptionPtr->fSharedWriteVars->fGroupData[i].fTimeStamp; } deviceDescriptionPtr->fDCLReadPos = 0; deviceDescriptionPtr->fBufWritePos = 0; deviceDescriptionPtr->fFrameBufferPos = 0; deviceDescriptionPtr->fDCLSavedWritePos = NULL; deviceDescriptionPtr->fDCLSavedPacketNum = 0; // Map the shared DCL program data buffer result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,kDVNumOutputFrames+6,mach_task_self(), &deviceDescriptionPtr->fDCLBuffer,&shmemSize,kIOMapAnywhere); FailIf(result != noErr, Exit); } deviceDescriptionPtr->fWaitingStartWrite = 1; deviceDescriptionPtr->fSharedVars->fReader = deviceDescriptionPtr->fSharedVars->fWriter = 0; deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fSharedVars->fDroppedFrames; deviceDescriptionPtr->fOldRead = deviceDescriptionPtr->fSharedVars->fReader; Exit: syslog(LOG_INFO, "enable write, result %x\n", result); return result; } static OSStatus disableWrite(DeviceDescription *deviceDescriptionPtr) { unsigned int size; OSStatus result; size = 0; result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVWriteStop, NULL, 0, NULL, &size); if(deviceDescriptionPtr->fOldWriteTimeStamps) { DisposePtr((Ptr)deviceDescriptionPtr->fOldWriteTimeStamps); deviceDescriptionPtr->fOldWriteTimeStamps = NULL; } syslog(LOG_INFO, "disable write\n"); return result; } static OSStatus sendMsg(IsochComponentInstancePtr ih, UInt32 request, void *params) { IsochComponentGlobalsPtr g = &globals; SendMsg msg; bzero( &msg, sizeof(msg)); msg.msgHdr.msgh_remote_port = g->fNotifyMachPort; msg.msgHdr.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND ); msg.msgHdr.msgh_size = sizeof(msg); msg.msgHdr.msgh_id = kDVRequestID; msg.dvRequest.fRequest = request; msg.dvRequest.fInstance = ih; msg.dvRequest.fParams = params; return mach_msg(&msg.msgHdr, MACH_SEND_MSG, msg.msgHdr.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); } static OSStatus addDevice(IsochComponentGlobalsPtr g, io_object_t obj, DeviceDescriptionPtr *deviceIDPtr) { OSErr result = noErr; QTAtom deviceAtom, isocAtom; DeviceDescriptionPtr deviceDescriptionPtr; IDHDeviceStatus deviceStatus; UInt32 standard; Boolean hasSDL; UInt32 devIndex; UInt64 newGUID; ComponentDescription clkDesc; CFDictionaryRef properties; CFNumberRef dataDesc; CFBooleanRef ntscDesc; CFBooleanRef sdlDesc; RecordEventLogger( 'isoc', 'addv', (int)g, obj); //syslog(LOG_INFO,"addDevice: service 0x%x\n", obj); ++g->seed; result = IORegistryEntryCreateCFProperties(obj, &properties, kCFAllocatorDefault, kNilOptions); if(result != noErr) return result; dataDesc = (CFNumberRef)CFDictionaryGetValue(properties, CFSTR("GUID")); CFNumberGetValue(dataDesc, kCFNumberSInt64Type, &newGUID); // fprintf(stderr,"Found device GUID: 0x%x%08x\n", // (int)(newGUID>>32), (int)(newGUID & 0xffffffff)); ntscDesc = (CFBooleanRef)CFDictionaryGetValue(properties, CFSTR("NTSC")); standard = ntscIn; if(ntscDesc && ! CFBooleanGetValue(ntscDesc)) { standard = palIn; } sdlDesc = (CFBooleanRef)CFDictionaryGetValue(properties, CFSTR("SDL")); hasSDL = false; if(sdlDesc && CFBooleanGetValue(sdlDesc)) { hasSDL = true; } CFRelease(properties); // look for existing device for( devIndex=0; devIndex < g->nDevices; ++devIndex) { deviceDescriptionPtr = &g->deviceDescription[devIndex]; if (newGUID == deviceDescriptionPtr->fGUID) { deviceDescriptionPtr->fID = obj; *deviceIDPtr = deviceDescriptionPtr; //syslog(LOG_INFO,"Found device, index %d\n", devIndex); // Get device back to old state if(deviceDescriptionPtr->fConnected) { int numFrames; unsigned int size; result = IOServiceOpen(deviceDescriptionPtr->fID, mach_task_self(), 11, &deviceDescriptionPtr->fConnection); if (result != kIOReturnSuccess) { return result; } #if 0 // If not real-time, Set buffer size, 10 frames seems enough. numFrames = 10; size = 0; io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVSetNumOutputFrames, &numFrames, 1, NULL, &size); #endif if(deviceDescriptionPtr->readLocks) { enableRead(deviceDescriptionPtr); } if(deviceDescriptionPtr->writeLocks) { enableWrite(deviceDescriptionPtr); } } return noErr; // All Done! } } do { Str255 cameraName; deviceDescriptionPtr = &g->deviceDescription[g->nDevices]; deviceDescriptionPtr->fGlobals = g; deviceDescriptionPtr->fID = obj; #ifdef DRAWRINGBUFFERGRAPH deviceDescriptionPtr->fScreenBaseAddr = 0; #endif result = registerDevice(deviceDescriptionPtr); if(noErr != result) break; RecordEventLogger( 'isoc', 'updt', 'add ', 'reg '); // add its description g->nDevices++; //*deviceID = ih->nDevices; deviceDescriptionPtr->fGUID = newGUID; // add the device standard (PAL, NTSC) deviceDescriptionPtr->standard = standard; deviceDescriptionPtr->active = true; deviceDescriptionPtr->fHasSDL = hasSDL; // find clock component // wouldn't it be better for us to open an instance on OpenDevice, set FWClockPrivLocalReference, etc. clkDesc.componentType = clockComponentType; clkDesc.componentSubType = 'fwcy'; clkDesc.componentManufacturer = 'appl'; clkDesc.componentFlags = 0L; clkDesc.componentFlagsMask = 0L; deviceDescriptionPtr->clock = FindNextComponent( deviceDescriptionPtr->clock, &clkDesc); // Look for FireWire clock component FailMessage( deviceDescriptionPtr->clock == nil); // create device description atom structure result = QTNewAtomContainer( &deviceDescriptionPtr->deviceContainer); if( result != noErr)break; // add a device atom result = QTInsertChild( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, (long) deviceDescriptionPtr, 0, 0, nil, &deviceAtom); if( result != noErr)break; // add the unique 64 bit FireWire GUID id to device atom result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHUniqueIDType, 0, 0, sizeof(newGUID), &newGUID, nil); if( result != noErr)break; result = cameraNameLookup(deviceDescriptionPtr, cameraName); if( result != noErr)break; result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHNameAtomType, 0, 0, cameraName[0] + 1, cameraName, nil); // add the IDH unique id to device atom result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHDeviceIDType, 0, 0, sizeof(deviceDescriptionPtr), &deviceDescriptionPtr, nil); if( result != noErr)break; // create a device status structure and add it to the device atom deviceStatus.version = 1; deviceStatus.physicallyConnected = true; deviceStatus.readEnabled = false; deviceStatus.writeEnabled = false; deviceStatus.exclusiveAccess = false; deviceStatus.currentBandwidth = 1; deviceStatus.currentChannel = 0; deviceStatus.inputStandard = standard; deviceStatus.deviceActive = false; result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo, 0, 0, sizeof( IDHDeviceStatus), &deviceStatus, nil); if( result != noErr)break; // add isoch descriptions to structure result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHIsochServiceAtomType, 0, 0, 0, nil, &isocAtom); if( result != noErr)break; // add the configs to the isoc atom result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard, false); if( result != noErr)break; if(hasSDL) { result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard, true); if( result != noErr)break; } if( standard == ntscIn) { result = setup48kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); if( result != noErr)break; result = setup32kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); if( result != noErr)break; } else // PAL audio { result = setup44kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); if( result != noErr)break; } *deviceIDPtr = deviceDescriptionPtr; return noErr; } while(false); return result; } static void deviceArrived(void *refcon, io_iterator_t iterator ) { io_object_t obj; IsochComponentGlobalsPtr ih = (IsochComponentGlobalsPtr)refcon; while(obj = IOIteratorNext(iterator)) { OSErr result; DeviceDescriptionPtr deviceDescriptionPtr; result = addDevice(ih, obj, &deviceDescriptionPtr); if(result == noErr) { postEvent(ih, (IDHDeviceID)deviceDescriptionPtr, kIDHEventDeviceAdded); // Request notification of messages IOServiceAddInterestNotification(ih->fNotifyPort, deviceDescriptionPtr->fID, kIOGeneralInterest, deviceMessage, deviceDescriptionPtr, &deviceDescriptionPtr->fNotification); } } } #define TIMING 0 /* raw read of the timebase register */ void clock_get_uptime( register AbsoluteTime *result) { #ifdef __ppc__ register UInt32 hic; do { asm volatile(" mftbu %0" : "=r" (result->hi)); asm volatile(" mftb %0" : "=r" (result->lo)); asm volatile(" mftbu %0" : "=r" (hic)); } while (hic != result->hi); #else result->lo = 0; result->hi = 0; #endif /* __ppc__ */ } #if TIMING #define WATCHDOG 1 #if WATCHDOG int RTThreadRunning; AbsoluteTime startTime; pthread_t watchThread; // Check for work thread running too long static void watchdog_thread_start(IsochComponentGlobalsPtr g) { double divisor; unsigned int delta; unsigned int abs_to_ns_num; unsigned int abs_to_ns_denom; unsigned int proc_to_abs_num; unsigned int proc_to_abs_denom; unsigned long long start, stop; int elapsed_msecs; (void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom, &proc_to_abs_num, &proc_to_abs_denom); divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000000; while (1) { if(RTThreadRunning) { AbsoluteTime now; clock_get_uptime(&now); start = (((unsigned long long)startTime.hi) << 32) | (unsigned long long)((unsigned int)(startTime.lo)); stop = (((unsigned long long)now.hi) << 32) | (unsigned long long)((unsigned int)(now.lo)); elapsed_msecs = (int)(((double)(stop - start)) / divisor); if(elapsed_msecs>100) { syslog(LOG_INFO, "Thread running for %d mSec\n", elapsed_msecs); *(int *)0 = 0xdeadbeef; // Find out why! } } usleep(30000); } } #endif #endif static void incrementWriteBuffer(DeviceDescription *deviceDescriptionPtr) { deviceDescriptionPtr->fSharedVars->fWriter += 1; // release buffer if(deviceDescriptionPtr->fWaitingStartWrite && deviceDescriptionPtr->fSharedVars->fWriter == 4) { unsigned int size = 0; io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVWriteStart, NULL, 0, NULL, &size); deviceDescriptionPtr->fWaitingStartWrite = 0; } } static void silenceFrame(DeviceDescription *deviceDescriptionPtr, UInt8* frame) { UInt32 i,j,k,n; UInt8 *tPtr; // Get DSF flag in byte 3 of header (Blue Book p. 113) tPtr = frame; if ((tPtr[3] &= 0x80) == 0) n=10; // ntsc else n=12; // pal if(deviceDescriptionPtr->fOutputMode & 4) // SDL n /= 2; // Yet another attempt ... // Mute all the audio samples for (i=0;ifActiveHead; if(pb && !waiting) { if(deviceDescriptionPtr->fWaitingStartWrite) { unsigned int size = 0; io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVWriteStart, NULL, 0, NULL, &size); deviceDescriptionPtr->fWaitingStartWrite = 0; } client->fActiveHead = (IDHParameterBlock *)pb->reserved1; if(client->fActiveHead == NULL) client->fActiveTail = NULL; pb->actualCount = deviceDescriptionPtr->fBufSize; pb->result = noErr; //syslog(LOG_INFO, "write callback, buffer = %p\n", pb->buffer); //syslog(LOG_INFO, "pb %p = req %d actual %d\n", // pb, pb->requestedCount, pb->actualCount); if(pb->completionProc) { err = pb->completionProc((IDHGenericEvent *)pb, pb->refCon); if(err != noErr) { syslog(LOG_INFO, "write callback for pb %p returned error %d\n", pb, err); } } } if(client->fActiveHead) { pb = client->fActiveHead; // We have to copy the buffer because QuickTime only uses one buffer to send data to us, // so if they drop a frame we don't have anything to send (because they are overwriting the // buffer with new data) bcopy(pb->buffer, (UInt8 *)deviceDescriptionPtr->bufMem[0], deviceDescriptionPtr->fBufSize); } else { //syslog(LOG_INFO, "Waiting for next IDHWrite, %d DCL blocks free\n", slack); if(slack < 3) { // No new frame to write, re-use the last one, after muting the audio deviceDescriptionPtr->fSharedVars->fDroppedFrames++; dropMsg(deviceDescriptionPtr); silenceFrame(deviceDescriptionPtr, (UInt8 *)deviceDescriptionPtr->bufMem[0]); } else { return NULL; // OK to wait for next IDHWrite } } deviceDescriptionPtr->fFrameBufferPos = 0; return (UInt8 *)deviceDescriptionPtr->bufMem[0]; } static int fillDCLGroup(DeviceDescription *deviceDescriptionPtr, IsochComponentInstancePtr client, int group, int slack) { UInt8 *dclPtr; UInt8 *dataPtr; UInt32 dataSize = deviceDescriptionPtr->fSharedWriteVars->fPacketDataSize; UInt32 packetSize = deviceDescriptionPtr->fSharedWriteVars->fAlignedPacketSize; int i; int start; // If we're waiting for a new frame, restore the current DCL pointer if(deviceDescriptionPtr->fDCLSavedWritePos != NULL) { dclPtr = deviceDescriptionPtr->fDCLSavedWritePos; dataPtr = getNextFrame(deviceDescriptionPtr, client, slack, true); //syslog(LOG_INFO, "Waiting for next frame, new frame = 0x%x\n", dataPtr); if(dataPtr == NULL) return 0; // Waiting for next frame. deviceDescriptionPtr->fDCLSavedWritePos = NULL; // Got a frame, carry on start = deviceDescriptionPtr->fDCLSavedPacketNum; deviceDescriptionPtr->fDCLSavedPacketNum = 0; } else { dclPtr = (UInt8 *)deviceDescriptionPtr->fDCLBuffer + deviceDescriptionPtr->fSharedWriteVars->fGroupData[group].fDataOffset; start = 0; } if(deviceDescriptionPtr->fWaitingStartWrite) { if(!client->fActiveHead) { return 0; // No data, not running yet. } else { bcopy(client->fActiveHead->buffer, (UInt8 *)deviceDescriptionPtr->bufMem[0], deviceDescriptionPtr->fBufSize); } } dataPtr = (UInt8 *)deviceDescriptionPtr->bufMem[0]; dataPtr += deviceDescriptionPtr->fFrameBufferPos; for(i=start; ifSharedWriteVars->fGroupSize; i++) { // check for buffer crossing page if (((int) (dclPtr + packetSize) & 0x0fff) < packetSize) { // if it does, increment buffer pointer // and lop off page rollover to start at next page dclPtr += packetSize; dclPtr = (UInt8 *)((int)dclPtr & 0xfffff000); } bcopy(dataPtr, dclPtr+8, dataSize); dataPtr += dataSize; deviceDescriptionPtr->fFrameBufferPos += dataSize; dclPtr += packetSize; if(deviceDescriptionPtr->fFrameBufferPos >= deviceDescriptionPtr->fBufSize) { dataPtr = getNextFrame(deviceDescriptionPtr, client, slack, false); if(dataPtr == NULL) { deviceDescriptionPtr->fDCLSavedWritePos = dclPtr; deviceDescriptionPtr->fDCLSavedPacketNum = i+1; return 0; // Waiting for next frame. } deviceDescriptionPtr->fFrameBufferPos = 0; deviceDescriptionPtr->fDCLSavedWritePos = NULL; deviceDescriptionPtr->fDCLSavedPacketNum = 0; } } return 1; } static void processWrites(DeviceDescription *deviceDescriptionPtr) { int i; int changed; int done; int pos; int emptyBlocks; int numGroups = deviceDescriptionPtr->fSharedWriteVars->fNumGroups; IsochComponentInstancePtr client; changed = 0; client = deviceDescriptionPtr->fOpenClients[0]; // First find out where the hardware is pos = deviceDescriptionPtr->fDCLReadPos; for(i=pos; i< pos+numGroups; i++) { int mod = i % numGroups; if(deviceDescriptionPtr->fOldWriteTimeStamps[mod] != deviceDescriptionPtr->fSharedWriteVars->fGroupData[mod].fTimeStamp) { deviceDescriptionPtr->fOldWriteTimeStamps[mod] = deviceDescriptionPtr->fSharedWriteVars->fGroupData[mod].fTimeStamp; deviceDescriptionPtr->fDCLReadPos = i; } } // We try to fill ~30ms of the DCL buffer emptyBlocks = numGroups-(deviceDescriptionPtr->fBufWritePos - deviceDescriptionPtr->fDCLReadPos); if(emptyBlocks >= numGroups && !deviceDescriptionPtr->fWaitingStartWrite) { syslog(LOG_INFO, "DCL wrap!!: %d\n", emptyBlocks); } if(emptyBlocks>3) emptyBlocks = 3; done = 0; for(i=0; ifBufWritePos + i) % numGroups, deviceDescriptionPtr->fBufWritePos+done - deviceDescriptionPtr->fDCLReadPos); if(!ok) break; done += ok; } deviceDescriptionPtr->fBufWritePos += done; } static int processReads(DeviceDescription *deviceDescriptionPtr) { int doneFrames = 0; int frameIndex; IsochComponentInstancePtr client; int i; frameIndex = deviceDescriptionPtr->fSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames; if(deviceDescriptionPtr->fSharedVars->fReader + 1 < deviceDescriptionPtr->fSharedVars->fWriter) { UInt8 *buffer = (UInt8 *)deviceDescriptionPtr->bufMem[frameIndex]; UInt32 frameSize = deviceDescriptionPtr->fSharedVars->fFrameSize[frameIndex]; // Lock buffer while we process stuff deviceDescriptionPtr->fBufferLocks[frameIndex]++; if(deviceDescriptionPtr->fOldDrop < deviceDescriptionPtr->fSharedVars->fDroppedFrames) { dropMsg(deviceDescriptionPtr); } for(i=0; ifOpenClients[i]; if(client) { if(client->fClientIndex != i) { syslog(LOG_INFO, "processReads: client %p of %p index is %d not %d\n", client, deviceDescriptionPtr, client->fClientIndex, i); } if(client->fHead) { IDHParameterBlock *pb = client->fHead; OSStatus err; pb->actualCount = frameSize; if(pb->buffer != nil) { // copy frame bcopy(buffer, pb->buffer, frameSize); } else { deviceDescriptionPtr->fBufferLocks[frameIndex]++; pb->buffer = buffer; } client->fHead = (IDHParameterBlock *)pb->reserved1; if(client->fHead == NULL) client->fTail = NULL; pb->result = noErr; //syslog(LOG_INFO, "read callback, buffer = %p\n", pb->buffer); //syslog(LOG_INFO, "pb %p = req %d actual %d\n", // pb, pb->requestedCount, pb->actualCount); err = pb->completionProc((IDHGenericEvent *)pb, pb->refCon); if(err != noErr) { syslog(LOG_INFO, "read callback for pb %p returned error %d\n", pb, err); } doneFrames++; } } } // unlock buffer deviceDescriptionPtr->fBufferLocks[frameIndex]--; if(doneFrames && deviceDescriptionPtr->fBufferLocks[frameIndex] == 0) deviceDescriptionPtr->fSharedVars->fReader += 1; // release buffer } return doneFrames; } static void queueWrite(IsochComponentInstancePtr client, IDHParameterBlock *pb) { if(pb->buffer) { if(client->fActiveTail == NULL) { client->fActiveHead = pb; } else client->fActiveTail->reserved1 = (UInt32)pb; client->fActiveTail = pb; } else { if(client->fTail == NULL) client->fHead = pb; else client->fTail->reserved1 = (UInt32)pb; client->fTail = pb; } pb->reserved1 = 0; } void processOpen(IsochComponentInstancePtr ih, DeviceDescription *deviceDescriptionPtr, UInt32 permissions) { ComponentResult result = noErr; int i; FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); // trying to reopen for read or write? if( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForReadTransactions) goto Exit; // don't do anything if( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForWriteTransactions) goto Exit; // don't do anything // check for switching directions before opening FailWithAction( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForWriteTransactions, result = kIDHErrDeviceInUse, Exit); FailWithAction( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForReadTransactions, result = kIDHErrDeviceInUse, Exit); // if user is opening for read, make sure device isn't already opened for writes if( permissions & kIDHOpenForReadTransactions) { FailWithAction( deviceDescriptionPtr->writeLocks, result = kIDHErrDeviceInUse, Exit); if( deviceDescriptionPtr->readLocks == 0) { result = enableRead(deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); } ++deviceDescriptionPtr->readLocks; // keep track of read count RecordEventLogger( 'open', ' Now', ih, deviceDescriptionPtr->readLocks); } // if user is opening for write, make sure device isn't already opened if( permissions & kIDHOpenForWriteTransactions) { FailWithAction( deviceDescriptionPtr->readLocks || deviceDescriptionPtr->writeLocks, result = kIDHErrDeviceInUse, Exit); result = enableWrite(deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); deviceDescriptionPtr->writeLocks = 1; // keep track of write count } // if( permissions & kIDHOpenWithExclusiveAccess) // deviceDescriptionPtr->exclusiveAccess = true; ih->permissions = permissions; // save the permissions // Setup device->component pointer for(i=0; ifOpenClients[i]) { deviceDescriptionPtr->fOpenClients[i] = ih; ih->fClientIndex = i; break; } } Exit: ih->fSyncResult = result; signalSync(&ih->fSyncRequest, 1); } void processClose(IsochComponentInstancePtr ih, DeviceDescription *deviceDescriptionPtr) { if( ih->permissions & kIDHOpenForReadTransactions) // tear down read { if( --deviceDescriptionPtr->readLocks <= 0) // is device completely freed by clients? { disableRead(deviceDescriptionPtr); // volatile int *fWriter,*fReader,*fDrop,*fStatus; //if(deviceDescriptionPtr->fSharedVars) { // printf("fWriter: %ld", deviceDescriptionPtr->fSharedVars->fWriter); // printf(" fReader: %ld", deviceDescriptionPtr->fSharedVars->fReader); // printf(" fDrop: %ld", deviceDescriptionPtr->fSharedVars->fDroppedFrames); // printf(" fStatus: %ld", deviceDescriptionPtr->fSharedVars->fStatus); // printf("\n"); //} //deviceDescriptionPtr->exclusiveAccess = false; } } if( ih->permissions & kIDHOpenForWriteTransactions) // tear down write { if( --deviceDescriptionPtr->writeLocks <= 0) // is device completely freed by clients? { disableWrite(deviceDescriptionPtr); //if(deviceDescriptionPtr->fSharedVars) { // printf("fWriter: %ld", deviceDescriptionPtr->fSharedVars->fWriter); // printf(" fReader: %ld", deviceDescriptionPtr->fSharedVars->fReader); // printf(" fDrop: %ld", deviceDescriptionPtr->fSharedVars->fDroppedFrames); // printf(" fStatus: %ld", deviceDescriptionPtr->fSharedVars->fStatus); // printf("\n"); //} //deviceDescriptionPtr->exclusiveAccess = false; } } deviceDescriptionPtr->fOpenClients[ih->fClientIndex] = nil; ih->fSyncResult = noErr; signalSync(&ih->fSyncRequest, 1); } static void processCancelPendingIO(IsochComponentInstancePtr client) { while(client->fHead) { IDHParameterBlock *pb = client->fHead; //syslog(LOG_INFO, "Cancelling IO %p, buffer = %p\n", pb, pb->buffer); client->fHead = (IDHParameterBlock *)pb->reserved1; pb->reserved1 = NULL; } client->fTail = NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void DVIsoch_thread_start(IsochComponentGlobalsPtr g) { ReceiveMsg msg; kern_return_t err; int delay; #if TIMING double divisor; int worst_sched = 0; int worst_callback = 0; int worst_msg = 0; { unsigned int delta; unsigned int abs_to_ns_num; unsigned int abs_to_ns_denom; unsigned int proc_to_abs_num; unsigned int proc_to_abs_denom; (void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom, &proc_to_abs_num, &proc_to_abs_denom); divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000000; } #endif deviceArrived(g, g->fMatchEnumer); signalSync(&g->fGlobalsState, 1); delay = 15; // 1/2 a frame while(true) { int dev; #if TIMING AbsoluteTime timestamp1; AbsoluteTime timestamp2; unsigned long long start, stop; int elapsed_msecs; #endif DeviceDescription *deviceDescriptionPtr; // deviceDescriptionPtr = (DeviceDescription *)ih->deviceID; for(dev = 0; devnDevices; dev++) { deviceDescriptionPtr = &g->deviceDescription[dev]; // Process I/O queues if(deviceDescriptionPtr) { #if TIMING clock_get_uptime(×tamp1); #endif if(deviceDescriptionPtr->writeLocks) processWrites(deviceDescriptionPtr); if(deviceDescriptionPtr->readLocks) processReads(deviceDescriptionPtr); #if TIMING clock_get_uptime(×tamp2); start = (((unsigned long long)timestamp1.hi) << 32) | (unsigned long long)((unsigned int)(timestamp1.lo)); stop = (((unsigned long long)timestamp2.hi) << 32) | (unsigned long long)((unsigned int)(timestamp2.lo)); elapsed_msecs = (int)(((double)(stop - start)) / divisor); if(elapsed_msecs > worst_callback) { pKGSysCall_Insert (kIOFWDVTrace, 'call', elapsed_msecs, 0, 0, 0, 0); syslog(LOG_INFO, "callback delay %d mSec\n", elapsed_msecs); worst_callback = elapsed_msecs; } #endif } } #if TIMING clock_get_uptime(×tamp1); #if WATCHDOG RTThreadRunning=0; #endif #endif err = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, //err = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, 0, sizeof(msg), g->fNotifyMachPort, delay, MACH_PORT_NULL); #if TIMING #if WATCHDOG clock_get_uptime(&startTime); RTThreadRunning=1; #endif clock_get_uptime(×tamp2); start = (((unsigned long long)timestamp1.hi) << 32) | (unsigned long long)((unsigned int)(timestamp1.lo)); stop = (((unsigned long long)timestamp2.hi) << 32) | (unsigned long long)((unsigned int)(timestamp2.lo)); elapsed_msecs = (int)(((double)(stop - start)) / divisor); if(elapsed_msecs > worst_sched) { pKGSysCall_Insert (kIOFWDVTrace, 'schd', elapsed_msecs, 0, 0, 0, 0); syslog(LOG_INFO, "schedule delay %d mSec\n", elapsed_msecs); worst_sched = elapsed_msecs; } #endif if(err == MACH_MSG_SUCCESS) { IsochComponentInstancePtr client; switch (msg.msgHdr.msgh_id) { case kOSNotificationMessageID: IODispatchCalloutFromMessage(NULL, &msg.msgHdr, g->fNotifyPort); break; case kDVRequestID: client = msg.body.dvRequest.fInstance; deviceDescriptionPtr = (DeviceDescriptionPtr)client->deviceID; switch(msg.body.dvRequest.fRequest) { case kComponentCloseSelect: pthread_exit(NULL); break; case kIDHReadSelect: { IDHParameterBlock *pbNew = (IDHParameterBlock *)msg.body.dvRequest.fParams; if(client) { if(client->fTail == NULL) client->fHead = pbNew; else client->fTail->reserved1 = (UInt32)pbNew; client->fTail = pbNew; } pbNew->reserved1 = 0; break; } case kIDHWriteSelect: { IDHParameterBlock *pbNew = (IDHParameterBlock *)msg.body.dvRequest.fParams; if(client) { queueWrite(client, pbNew); } break; } case kIDHCancelPendingIOSelect: if(client) { processCancelPendingIO(client); } client->fSyncResult = noErr; signalSync(&client->fSyncRequest, 1); break; case kIDHCloseDeviceSelect: processClose(client, deviceDescriptionPtr); break; case kIDHOpenDeviceSelect: processOpen(client, deviceDescriptionPtr, (UInt32)msg.body.dvRequest.fParams); break; default: printf("DVIsoch : Unknown DVRequest %ld, params %p\n", msg.body.dvRequest.fRequest, msg.body.dvRequest.fParams); } break; default: printf("DVIsoch : Unexpected msg id %d\n", msg.msgHdr.msgh_id); } #if TIMING clock_get_uptime(×tamp1); start = (((unsigned long long)timestamp2.hi) << 32) | (unsigned long long)((unsigned int)(timestamp2.lo)); stop = (((unsigned long long)timestamp1.hi) << 32) | (unsigned long long)((unsigned int)(timestamp1.lo)); elapsed_msecs = (int)(((double)(stop - start)) / divisor); if(elapsed_msecs > worst_msg) { pKGSysCall_Insert (kIOFWDVTrace, 'msg ', elapsed_msecs, 0, 0, 0, 0); syslog(LOG_INFO, "message process delay %d mSec for message %d (%d)\n", elapsed_msecs, msg.msgHdr.msgh_id, msg.body.dvRequest.fRequest); worst_msg = elapsed_msecs; } #endif } else if(err != MACH_RCV_TIMED_OUT) { printf("DVIsoch : Receive err 0x%x, size %d(max %ld)\n", err, msg.msgHdr.msgh_size, sizeof(msg)); } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static pascal ComponentResult FWDVComponentOpen(IsochComponentInstancePtr storage, ComponentInstance self) { kern_return_t err = noErr; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'open', 0, 0); if( nil == (storage = (IsochComponentInstancePtr)NewPtrClear(sizeof(IsochComponentInstance)))) return(MemError()); RecordEventLogger( 'isoc', 'ope2', (int)storage, 0); SetComponentInstanceStorage(self, (Handle) storage); // One-time initialization of globals if (!g->fMasterDevicePort) { policy_base_data_t thePolicyBase; host_priority_info_data_t priorityDefaults; int count; err = IOMasterPort(bootstrap_port, &g->fMasterDevicePort); if (err != KERN_SUCCESS) { RecordEventLogger( 'isoc', 'opep', (int)err, 0); return err; } g->fNotifyPort = IONotificationPortCreate(g->fMasterDevicePort); g->fNotifyMachPort = IONotificationPortGetMachPort(g->fNotifyPort); err = IOServiceAddMatchingNotification( g->fNotifyPort, kIOMatchedNotification, IOServiceMatching( kDVKernelDriverName ), deviceArrived, g, &g->fMatchEnumer ); if (err != kIOReturnSuccess) { return err; } err = mach_port_insert_right(mach_task_self(), g->fNotifyMachPort, g->fNotifyMachPort, MACH_MSG_TYPE_MAKE_SEND); FailWithVal( err != noErr, Exit, err); g->fGlobalsState = 0; err = pthread_mutex_init(&g->fGlobalsMutex, NULL); FailWithVal( err != noErr, Exit, err); err = pthread_cond_init(&g->fSyncCond, NULL); FailWithVal( err != noErr, Exit, err); err = pthread_attr_init(&g->fThreadAttr); FailWithVal( err != noErr, Exit, err); err = pthread_create(&g->fWorkThread, &g->fThreadAttr, (void *)DVIsoch_thread_start, g); FailWithVal( err != noErr, Exit, err); #if 0 // Set thread priority to default round-robin - count = HOST_PRIORITY_INFO_COUNT; // Get the recommended priority for running on this configuration err = host_info ( mach_host_self(), HOST_PRIORITY_INFO, (host_info_t)&priorityDefaults, &count); FailWithVal( err != noErr, Exit, err); thePolicyBase.rr.base_priority = priorityDefaults.user_priority; // = 31 in Puma //thePolicyBase.rr.base_priority = 63; //max allowable; thePolicyBase.rr.quantum = 10; // recommended by Bohman.. to be revisited. // set this thread's current scheduling policy to be RR err = thread_policy (pthread_mach_thread_np(g->fWorkThread), POLICY_RR, (policy_base_t)&thePolicyBase.rr, POLICY_RR_BASE_COUNT, FALSE ); #endif #if 1 { double mult; unsigned int delta; unsigned int abs_to_ns_num; unsigned int abs_to_ns_denom; unsigned int proc_to_abs_num; unsigned int proc_to_abs_denom; thread_time_constraint_policy_data_t constraints; (void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom, &proc_to_abs_num, &proc_to_abs_denom); mult = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000000; constraints.period = 15*mult; constraints.computation = 2*mult; constraints.constraint = 30*mult; constraints.preemptible = TRUE; err = thread_policy_set(pthread_mach_thread_np(g->fWorkThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT); #if WATCHDOG if(watchThread == 0) { err = pthread_create(&watchThread, &g->fThreadAttr, (void *)watchdog_thread_start, g); constraints.period = 30*mult; constraints.computation = 1*mult; constraints.constraint = 30*mult; constraints.preemptible = TRUE; err = thread_policy_set(pthread_mach_thread_np(watchThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT); } #endif } #endif #if 0 // more than Window Manager, so moving windows etc. doesn't cause dropped frames. thePolicyBase.ts.base_priority = 72; //thePolicyBase.ts.base_priority = 127; // max allowable err = thread_policy(pthread_mach_thread_np(g->fWorkThread), POLICY_TIMESHARE, (policy_base_t)&thePolicyBase.ts, POLICY_TIMESHARE_BASE_COUNT, TRUE); #endif FailWithVal( err != noErr, Exit, err); } // Wait for work thread to finish initializing globals waitSync(&g->fGlobalsState); g->fNumInstances++; Exit: return( err ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static pascal ComponentResult FWDVComponentClose(IsochComponentInstancePtr ih, ComponentInstance self) { int i; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'clos', ih, self); if( !ih) return( noErr ); if(ih->hasDeviceControl) { DeviceDescriptionPtr deviceDescriptionPtr; if(findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr) == noErr) closeDeviceControl( ih, deviceDescriptionPtr); } if( ih->permissions ) FWDVIDHCloseDevice(ih); g->fNumInstances--; if(g->fNumInstances == 0) { if(g->fWorkThread) { void *status; int err; sendMsg(ih, kComponentCloseSelect, ih); err = pthread_join(g->fWorkThread, &status); } // Free all mach ports etc. for(i=0; inDevices; i++) { DeviceDescriptionPtr dev = &g->deviceDescription[i]; if(dev->fConnection) { IOConnectRelease(dev->fConnection); dev->fConnection = NULL; } dev->fConnected = 0; if(dev->fNotification) { IOObjectRelease(dev->fNotification); dev->fNotification = NULL; } if(dev->fID) { IOObjectRelease(dev->fID); dev->fID = NULL; } } if(g->fMatchEnumer) IOObjectRelease(g->fMatchEnumer); if(g->fNotifyPort) IONotificationPortDestroy(g->fNotifyPort); g->fGlobalsState = 0; g->fMasterDevicePort = NULL; } DisposePtr((Ptr) ih); SetComponentInstanceStorage(self, (Handle) nil ); RecordEventLogger( 'isoc', 'clos', 'end ', 0); return( noErr ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static pascal ComponentResult FWDVComponentVersion(IsochComponentInstancePtr storage) { RecordEventLogger( 'isoc', 'vers', 0, 0); return 0x10001; } static pascal ComponentResult FWDVComponentRegister(IsochComponentInstancePtr storage) { // need to re-register with each source type? RecordEventLogger( 'isoc', 'reg ', 0, 0); return( noErr ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static pascal ComponentResult FWDVIDHGetDeviceList(IsochComponentInstancePtr storage, QTAtomContainer *deviceList ) { OSErr result = noErr; QTAtomContainer container = nil; int devIndex; UInt32 version; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'get ', 'dev ', 'list'); do { // create device atom list now result = QTNewAtomContainer( &container); if(result != noErr) break; // save seed result = QTInsertChild( container, kParentAtomIsContainer, kIDHSeedAtomType, 0, 0, sizeof( g->seed), &g->seed, nil); if(result != noErr) break; version = (DVVersion << 24) | (DVRevision << 16) | DVBuildNumber; // save isoch version result = QTInsertChild( container, kParentAtomIsContainer, kIDHIsochVersionAtomType, 0, 0, sizeof( UInt32), &version, nil); if(result != noErr) break; // save useCMP value result = QTInsertChild( container, kParentAtomIsContainer, kIDHUseCMPAtomType, 0, 0, sizeof( UInt32), &g->useCMP, nil); if(result != noErr) break; // save each active device for( devIndex=0; devIndexdeviceDescription[devIndex].fID != 0 && g->deviceDescription[devIndex].active) { result = QTInsertChildren( container, kParentAtomIsContainer, g->deviceDescription[devIndex].deviceContainer); if(result != noErr) break; } } *deviceList = container; return noErr; } while (false); if(container) { QTRemoveChildren( container, kParentAtomIsContainer); QTDisposeAtomContainer( container); } return result; } static pascal ComponentResult FWDVIDHSetDeviceConfiguration(IsochComponentInstancePtr ih, const QTAtomSpec *configID) { OSErr result = noErr; QTAtomSpec volatileAtomSpec; QTAtom nameAtom; IDHDeviceID previousDeviceID; DeviceDescription *deviceDescriptionPtr; IsochComponentGlobalsPtr g = &globals; Boolean isSDL; int numFrames; unsigned int size; RecordEventLogger( 'isoc', 'set ', 'conf', ih); FailWithAction( configID == nil, result = paramErr, Exit); FailWithAction( configID->container == nil, result = paramErr, Exit); // if the client is setting to the same config, then we are ok if( configID->container == ih->currentConfig.container && configID->atom == ih->currentConfig.atom) goto Exit; // device already in use, please close device first FailWithAction( ih->permissions != 0, result = kIDHErrDeviceInUse, Exit); previousDeviceID = ih->deviceID; volatileAtomSpec = *configID; result = getDeviceID( &volatileAtomSpec, &ih->deviceID); FailWithVal( result != noErr, Exit, result); result = checkSeed( g, &volatileAtomSpec); FailWithVal( result != noErr, Exit, result); ih->currentConfig = *configID; nameAtom = QTFindChildByIndex( configID->container, configID->atom, kIDHNameAtomType, 1, nil); if( nameAtom != nil) { Str255 name; long size; QTCopyAtomDataToPtr( configID->container, nameAtom, true, 255, name, &size); isSDL = !strncmp(name, "\pDV-SDL", *name); } else isSDL = false; result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); // Open device if(deviceDescriptionPtr->fConnection == NULL) { result = IOServiceOpen(deviceDescriptionPtr->fID, mach_task_self(), 11, &deviceDescriptionPtr->fConnection); if (result != kIOReturnSuccess) { goto Exit; } #if 0 // If not real time, Set buffer size, 10 frames seems enough. numFrames = 10; size = 0; io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVSetNumOutputFrames, &numFrames, 1, NULL, &size); #endif deviceDescriptionPtr->fConnected = 1; } FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); // if this client already has device control, free the previous connection if( previousDeviceID && previousDeviceID != ih->deviceID) { DeviceDescription *deviceDescriptionPtr2; result = findDeviceDescriptionforDevice( ih, previousDeviceID, &deviceDescriptionPtr2); FailWithVal( result != noErr, Exit, result); if(deviceDescriptionPtr2->fConnection) { IOConnectRelease(deviceDescriptionPtr2->fConnection); deviceDescriptionPtr2->fConnection = nil; } if(ih->hasDeviceControl) { result = closeDeviceControl( ih, deviceDescriptionPtr2); FailMessage( result != noErr); ih->hasDeviceControl = false; } } // Set output signal mode deviceDescriptionPtr->fOutputMode = 0; if(isSDL) deviceDescriptionPtr->fOutputMode |= 4; if(deviceDescriptionPtr->standard != ntscIn) deviceDescriptionPtr->fOutputMode |= 0x80; Exit: RecordEventLogger( 'isoc', 'set ', 'Exit', ih); return result; } static pascal ComponentResult FWDVIDHOpenDevice(IsochComponentInstancePtr ih, UInt32 permissions) { ComponentResult result = noErr; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'open', ' dev', ih, permissions); FailWithAction( permissions == 0, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); ih->fSyncRequest = 0; result = sendMsg(ih, kIDHOpenDeviceSelect, (void *)permissions); waitSync(&ih->fSyncRequest); result = ih->fSyncResult; FailWithVal( result != noErr, Exit, result); result = postEvent( g, ih->deviceID, (permissions & kIDHOpenForReadTransactions)?kIDHEventReadEnabled:kIDHEventWriteEnabled); FailWithVal( result != noErr, Exit, result); #ifdef DRAWRINGBUFFERGRAPH SetUpBlitGlobals((DeviceDescription *)ih->deviceID); #endif Exit: return result; } static pascal ComponentResult FWDVIDHCloseDevice(IsochComponentInstancePtr ih) { OSErr result = noErr; DeviceDescription *deviceDescriptionPtr; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'clos', ' dev', ih); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); if( ih->permissions == 0) // client has no open devices? goto Exit; result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); // find the device FailWithVal( result != noErr, Exit, result); if(globals.fWorkThread == pthread_self()) { processClose(ih, deviceDescriptionPtr); result = noErr; } else { ih->fSyncRequest = 0; result = sendMsg(ih, kIDHCloseDeviceSelect, 0); waitSync(&ih->fSyncRequest); result = ih->fSyncResult; FailWithVal( result != noErr, Exit, result); } result = postEvent( g, ih->deviceID, (ih->permissions & kIDHOpenForReadTransactions)?kIDHEventReadDisabled:kIDHEventWriteDisabled); FailWithVal( result != noErr, Exit, result); Exit: ih->permissions = 0; // make sure device is closed ih->fClientIndex = 0xdead; return result; } //еее USER BETTER KEEP HIS DEVICE LIST AROUND IF THIS IS TO MEAN ANYTHING static pascal ComponentResult FWDVIDHGetDeviceConfiguration(IsochComponentInstancePtr ih, QTAtomSpec *configID ) { OSErr result = noErr; RecordEventLogger( 'isoc', 'get ', 'dev ', 'conf'); FailWithAction( configID == nil, result = paramErr, Exit); FailWithAction( ih->currentConfig.container == nil || ih->currentConfig.atom == nil, result = kIDHErrDeviceNotConfigured, Exit); *configID = ih->currentConfig; Exit: return result; } static pascal ComponentResult FWDVIDHGetDeviceStatus(IsochComponentInstancePtr ih, const QTAtomSpec *devSpec, IDHDeviceStatus *status ) { OSErr result = noErr; IDHDeviceID deviceID = nil; QTAtom deviceInfoAtom, deviceAtom; QTAtomSpec volatileAtomSpec; long size; DeviceDescription *deviceDescriptionPtr; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'get ', 'stat', ih); FailWithAction( devSpec == nil, result = paramErr, Exit); FailWithAction( status == nil, result = paramErr, Exit); volatileAtomSpec = *devSpec; result = checkSeed( g, &volatileAtomSpec); if( result != noErr) goto Exit; result = getDeviceID( &volatileAtomSpec, &deviceID); FailWithVal( result != noErr, Exit, result); result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr); // find description for this device FailWithVal( result != noErr, Exit, result); deviceAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil); FailWithAction( deviceAtom == nil, result = kIDHErrDeviceList, Exit); // find device status for this device deviceInfoAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo, 1, nil); FailWithAction( deviceInfoAtom == nil, result = kIDHErrDeviceList, Exit); QTLockContainer( deviceDescriptionPtr->deviceContainer); // get the value of the mediaType atom QTCopyAtomDataToPtr( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, true, sizeof( IDHDeviceStatus), status, &size); QTUnlockContainer( deviceDescriptionPtr->deviceContainer); status->version = 100; status->physicallyConnected = true; status->readEnabled = deviceDescriptionPtr->readLocks; status->writeEnabled = deviceDescriptionPtr->writeLocks; status->exclusiveAccess = 0;//deviceDescriptionPtr->exclusiveAccess; status->currentBandwidth = 0; status->currentChannel = 0; //еее need to make this work with camera tracking status->deviceActive = deviceDescriptionPtr->active; status->inputStandard = deviceDescriptionPtr->standard; // JKL *** what to to with this? does this mean deviceID, cameraFWClientID, or localNodeFWClientID // Think this is for clock to set the localFWReferenceID status->localNodeID = (PsuedoID) deviceDescriptionPtr->fID; result = QTSetAtomData( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, sizeof( IDHDeviceStatus), status); FailWithVal( result != noErr, Exit, result); Exit: return result; } static pascal ComponentResult FWDVIDHGetDeviceClock(IsochComponentInstancePtr ih, Component *clock ) { DeviceDescription *deviceDescriptionPtr; OSErr result = noErr; RecordEventLogger( 'isoc', 'get ', 'clok', 0); FailWithAction( clock == nil, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); // FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); *clock = deviceDescriptionPtr->clock; Exit: return result; } // can be called synchronously at task level only static pascal ComponentResult FWDVIDHRead(IsochComponentInstancePtr ih, IDHParameterBlock *pb) { OSErr result = noErr; DeviceDescription *deviceDescriptionPtr; RecordEventLogger( 'isoc', 'read', (unsigned long) ih, (unsigned long) pb ); //syslog(LOG_INFO, "FWDVIDHRead, completion = %p buffer = %p\n", pb->completionProc, pb->buffer); //syslog(LOG_INFO, "pb %p = req %d actual %d, result %d\n", // pb, pb->requestedCount, pb->actualCount, pb->result); FailWithAction( pb == nil, result = paramErr, Exit); // can't do sync reads in I/O thread //FailWithAction( pb->completionProc == nil && CurrentExecutionLevel() != kTaskLevel, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); FailWithAction( !(ih->permissions & kIDHOpenForReadTransactions), result = kIDHErrDeviceNotOpened, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); if( pb->completionProc == nil) // synchronous read { int frameIndex = deviceDescriptionPtr->fSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames; UInt8 *buffer = (UInt8 *)deviceDescriptionPtr->bufMem[frameIndex]; UInt32 frameSize; // wait for writer // if (*devices[refNum].fReader + 1 >= *devices[refNum].fWriter) return -1; if( deviceDescriptionPtr->fOldDrop < deviceDescriptionPtr->fSharedVars->fDroppedFrames) { dropMsg(deviceDescriptionPtr); } while (deviceDescriptionPtr->fSharedVars->fReader + 1 >= deviceDescriptionPtr->fSharedVars->fWriter) { usleep(15000); // about 1/2 a frame } frameSize = deviceDescriptionPtr->fSharedVars->fFrameSize[frameIndex]; pb->actualCount = frameSize; if(pb->buffer != nil) { // copy frame bcopy(buffer, pb->buffer, frameSize); deviceDescriptionPtr->fSharedVars->fReader += 1; // release buffer } else pb->buffer = buffer; pb->result = noErr; } else { pb->result = kIDHErrCompletionPending; //syslog(LOG_INFO, "FWDVIDHRead end, completion = %p buffer = %p\n", pb->completionProc, pb->buffer); //syslog(LOG_INFO, "pb %p = req %d actual %d, result %d\n", // pb, pb->requestedCount, pb->actualCount, pb->result); result = sendMsg(ih, kIDHReadSelect, pb); } Exit: #ifdef DRAWRINGBUFFERGRAPH BlitBufferGraph(deviceDescriptionPtr); #endif return result; } static pascal ComponentResult FWDVIDHReleaseBuffer(IsochComponentInstancePtr ih, IDHParameterBlock *pb) { OSErr result = noErr; int frameIndex; DeviceDescription *deviceDescriptionPtr; RecordEventLogger( 'isoc', 'rele', 'ase ', 'buff'); FailWithAction( pb == nil, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); frameIndex = deviceDescriptionPtr->fSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames; if(pb->buffer == (Ptr)deviceDescriptionPtr->bufMem[frameIndex]) { if(--deviceDescriptionPtr->fBufferLocks[frameIndex] == 0) deviceDescriptionPtr->fSharedVars->fReader += 1; // release buffer, this isn't quite right if several buffers are held. } Exit: return result; } static pascal ComponentResult FWDVIDHCancelPendingIO(IsochComponentInstancePtr ih, IDHParameterBlock *pb) { OSErr result = noErr; DeviceDescription *deviceDescriptionPtr; RecordEventLogger( 'isoc', 'canc', 'elIO', 0); FailWithAction( pb == nil, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); if(globals.fWorkThread == pthread_self()) { processCancelPendingIO(ih); result = noErr; } else { ih->fSyncRequest = 0; result = sendMsg(ih, kIDHCancelPendingIOSelect, pb); waitSync(&ih->fSyncRequest); result = ih->fSyncResult; } Exit: #ifdef DRAWRINGBUFFERGRAPH BlitBufferGraph(deviceDescriptionPtr); #endif return result; } // can be called synchronously at task level only static pascal ComponentResult FWDVIDHWrite(IsochComponentInstancePtr ih, IDHParameterBlock *pb) { OSErr result = noErr; DeviceDescription *deviceDescriptionPtr; RecordEventLogger( 'isoc', 'writ', ih, pb); FailWithAction( pb == nil, result = paramErr, Exit); // check for illegal condition FailWithAction( pb->completionProc == nil && pb->buffer == nil, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); if( pb->completionProc == nil) // synchronous write { pb->result = kIDHErrCompletionPending; result = sendMsg(ih, kIDHWriteSelect, pb); while (pb->result == kIDHErrCompletionPending) { usleep(15000); // about 1/2 a frame } } else { if(globals.fWorkThread == pthread_self()) { queueWrite(ih, pb); } else result = sendMsg(ih, kIDHWriteSelect, pb); } Exit: #ifdef DRAWRINGBUFFERGRAPH BlitBufferGraph(deviceDescriptionPtr); #endif return result; } static pascal ComponentResult FWDVIDHGetDeviceControl(IsochComponentInstancePtr ih, ComponentInstance *deviceControl) { ComponentResult result = noErr; DeviceDescription *deviceDescriptionPtr; RecordEventLogger( 'isoc', 'get ', 'dev ', 'ctrl'); if ( deviceControl == nil ) return(paramErr); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); // ======================================================================= // All should be good here from a device stand point, now open the device // control component. If the devc is not nil either we didn't release it // from close or the same client is calling open again. if ( deviceDescriptionPtr->deviceControlInstance == nil) { ComponentDescription devcDesc; Component devcComp; ComponentInstance devc; devcDesc.componentType = kDeviceControlComponentType; devcDesc.componentSubType = kDeviceControlSubtypeFWDV; devcDesc.componentManufacturer = 0; devcDesc.componentFlags = 0L; devcDesc.componentFlagsMask = 0L; devcComp = nil; devcComp = FindNextComponent( devcComp, &devcDesc); FailMessage( devcComp == nil); if ( devcComp ) { result = OpenAComponent(devcComp, &devc); FailWithVal( result != noErr, Exit, result); result = DeviceControlSetDeviceConnectionID(devc, (DeviceConnectionID) deviceDescriptionPtr->fConnection); FailWithVal( result != noErr, Exit, result); result = DeviceControlEnableAVCTransactions(devc); FailWithVal( result != noErr, Exit, result); deviceDescriptionPtr->deviceControlInstance = devc; } } if( ih->hasDeviceControl == false && deviceDescriptionPtr->deviceControlInstance != nil) { ih->hasDeviceControl = true; ++deviceDescriptionPtr->deviceControlCount; } *deviceControl = deviceDescriptionPtr->deviceControlInstance; FailMessage( *deviceControl == nil); Exit: return(result); } static pascal ComponentResult FWDVIDHUpdateDeviceList(IsochComponentInstancePtr ih, QTAtomContainer *deviceList ) { OSErr result = noErr; short nDVDevices, i; QTAtomSpec atomSpec; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'updt', 'dev ', 'list'); FailWithAction( deviceList == nil, result = paramErr, Exit); atomSpec.container = *deviceList; result = checkSeed( g, &atomSpec); // make sure the container is current if( result != noErr) goto Exit; // check for useCMP value changing if (result == noErr) { QTAtom useCMPAtom; UInt32 useCMPValue; useCMPAtom = QTFindChildByIndex(*deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil); if (useCMPAtom) { QTLockContainer(*deviceList); result = QTCopyAtomDataToPtr(*deviceList, useCMPAtom, true, 4, &useCMPValue, nil); QTUnlockContainer(*deviceList); if (result == noErr) g->useCMP = useCMPValue; } } // move all volatile atoms here nDVDevices = QTCountChildrenOfType( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType); for( i=0; ideviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil); FailIf( deviceAtomOld == nil, Exit); nameAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtomOld, kIDHNameAtomType, 1, nil); FailIf( nameAtomOld == nil, Exit); // get new name QTLockContainer( *deviceList); result = QTCopyAtomDataToPtr(*deviceList, nameAtomNew, true, 256, newName, &actualSize); QTUnlockContainer( *deviceList); FailWithVal( result != noErr, Exit, result); // update prefs file with new name // JKL, don't want to do this for now since FCP might be using this routine to toggle CMP // updateCameraName(&deviceDescriptionPtr->uniqueID, newName); // copy the new data into the current atom result = QTReplaceAtom( deviceDescriptionPtr->deviceContainer, nameAtomOld, *deviceList, nameAtomNew); FailWithVal( result != noErr, Exit, result); } Exit: return result; } static pascal ComponentResult FWDVIDHGetDeviceTime(IsochComponentInstancePtr ih, TimeRecord *time) { OSErr result = noErr; DeviceDescription *deviceDescriptionPtr; UInt32 info[2]; UInt64 cycles; int size; FailWithAction( time == nil, result = paramErr, Exit); FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result); FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); size = 2; result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection, kDVGetDeviceTime, NULL, 0, (int *)info, &size); cycles = info[0] * 8000; // Seconds converted to cycles cycles += (info[1] >> 12) & 0x1fff; time->value.lo = cycles & 0xffffffff; time->value.hi = (cycles >> 32) & 0xffffffff; time->scale = 8000; Exit: return result; } static pascal ComponentResult FWDVIDHNewNotification(IsochComponentInstancePtr ihc, IDHDeviceID deviceID, IDHNotificationProc notificationProc, void* userData, IDHNotificationID* notificationID) { UInt32 i; Boolean addedClient = false; OSErr result = noErr; IsochComponentGlobalsPtr g = &globals; RecordEventLogger( 'isoc', 'new ', 'noti', 'fy '); FailWithAction( notificationProc == nil, result = paramErr, Exit); FailWithAction( notificationID == nil, result = paramErr, Exit); i = 0; while (i < kMaxNotifications) { if (0 == g->clientNotification[i].deviceID) { g->clientNotification[i].deviceID = deviceID; g->clientNotification[i].notificationProc = notificationProc; g->clientNotification[i].events = 0; g->clientNotification[i].userData = userData; *notificationID = (UInt32)&g->clientNotification[i]; addedClient = true; break; } ++i; } if (!addedClient) // List is full. Unable to add addtional clients result = paramErr; Exit: return result; } static pascal ComponentResult FWDVIDHNotifyMeWhen(ComponentInstance idh, IDHNotificationID notificationID, IDHEvent events) { OSErr result = noErr; ClientNotification* clientNotification = (ClientNotification*)notificationID; RecordEventLogger( 'isoc', 'noti', 'when', events); FailWithAction( clientNotification == nil, result = paramErr, Exit); clientNotification->events = events; Exit: return result; } static pascal ComponentResult FWDVIDHCancelNotification(ComponentInstance idh, IDHNotificationID notificationID) { OSErr result = noErr; ClientNotification* clientNotification = (ClientNotification*)notificationID; RecordEventLogger( 'isoc', 'canc', 'el ', 'noti'); FailWithAction( clientNotification == nil, result = paramErr, Exit); clientNotification->events = 0; Exit: return result; } static pascal ComponentResult FWDVIDHDisposeNotification(ComponentInstance idh, IDHNotificationID notificationID) { OSErr result = noErr; ClientNotification* clientNotification = (ClientNotification*)notificationID; RecordEventLogger( 'isoc', 'disp', 'ose ', 'noti'); FailWithAction( clientNotification == nil, result = paramErr, Exit); clientNotification->deviceID = 0; Exit: return result; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DoCDispatchWS(x,p,s) \ case k ## x ## Select: \ /* printf("FWDV" #x "{"); */ \ { ComponentResult err; \ err = CallComponentFunctionWithStorageProcInfo( s, p, (ProcPtr) FWDV ## x, \ uppCall ## x ## ProcInfo ); \ /* printf("%ld}\n", err); */ \ return err; } #define DoDispatchWS(x,p,s) \ case k ## x ## Select: \ /* printf("FWDV" #x "{"); */ \ { ComponentResult err; \ err = CallComponentFunctionWithStorageProcInfo( s, p, (ProcPtr) FWDV ## x, \ upp ## x ## ProcInfo ); \ /* printf("%ld}\n", err); */ \ return err; } static pascal ComponentResult FWDVComponentCanDo(IsochComponentInstancePtr storage, short selector) { ComponentResult result; RecordEventLogger( 'isoc', 'cand', 0, 0); switch(selector) { /* Standard selectors */ case kComponentOpenSelect: case kComponentCloseSelect: case kComponentCanDoSelect: case kComponentVersionSelect: /* IDH selectors */ case kIDHGetDeviceListSelect: case kIDHGetDeviceConfigurationSelect: case kIDHSetDeviceConfigurationSelect: case kIDHGetDeviceStatusSelect: case kIDHGetDeviceClockSelect: case kIDHOpenDeviceSelect: case kIDHCloseDeviceSelect: case kIDHReadSelect: case kIDHWriteSelect: case kIDHNewNotificationSelect: case kIDHNotifyMeWhenSelect: case kIDHCancelNotificationSelect: case kIDHDisposeNotificationSelect: case kIDHReleaseBufferSelect: case kIDHCancelPendingIOSelect: case kIDHGetDeviceControlSelect: case kIDHUpdateDeviceListSelect: case kIDHGetDeviceTimeSelect: return(true); default: RecordEventLogger( 'isoc', 'cant', selector, 0); result = false; return (result); } } pascal ComponentResult FWDVICodecComponentDispatch(ComponentParameters *params, char ** storage) { ComponentResult result; /* If the selector is less than zero, it's a Component manager selector. */ if ( params->what < 0 ) { switch ( params->what ) { DoCDispatchWS( ComponentOpen, params, storage ); DoCDispatchWS( ComponentClose, params, storage ); DoCDispatchWS( ComponentRegister, params, storage ); DoCDispatchWS( ComponentCanDo, params, storage ); DoCDispatchWS( ComponentVersion, params, storage ); default : return (paramErr); } } /* * Here we dispatch the rest of our calls. We use the magic thing manager routine which * calls our subroutines with the proper parameters. The prototypes are in Image Codec.h. */ switch ( params->what ) { DoDispatchWS( IDHGetDeviceList, params, storage ); DoDispatchWS( IDHGetDeviceConfiguration, params, storage ); DoDispatchWS( IDHSetDeviceConfiguration, params, storage ); DoDispatchWS( IDHGetDeviceStatus, params, storage ); DoDispatchWS( IDHGetDeviceClock, params, storage ); DoDispatchWS( IDHOpenDevice, params, storage ); DoDispatchWS( IDHCloseDevice, params, storage ); DoDispatchWS( IDHRead, params, storage ); DoDispatchWS( IDHWrite, params, storage ); DoDispatchWS( IDHReleaseBuffer, params, storage ); DoDispatchWS( IDHCancelPendingIO, params, storage ); DoDispatchWS( IDHGetDeviceControl, params, storage ); DoDispatchWS( IDHUpdateDeviceList, params, storage ); DoDispatchWS( IDHGetDeviceTime, params, storage ); DoDispatchWS( IDHNewNotification, params, storage ); DoDispatchWS( IDHNotifyMeWhen, params, storage ); DoDispatchWS( IDHCancelNotification, params, storage ); DoDispatchWS( IDHDisposeNotification, params, storage ); default: { int len = params->paramSize/4; int i; printf("IDH unimp:%d %d ", params->what, params->paramSize); for(i=0; iparams[i]); printf("\n"); result = paramErr; return(result); } } } #ifdef DRAWRINGBUFFERGRAPH static void SetUpBlitGlobals(DeviceDescriptionPtr ddp) { GDHandle gdh = GetMainDevice(); if (gdh) { ddp->fScreenBaseAddr = gdh[0]->gdPMap[0]->baseAddr; ddp->fRowBytes = gdh[0]->gdPMap[0]->rowBytes & 0x3FFF; ddp->fPixDepth = gdh[0]->gdPMap[0]->pixelSize; } } #define spacerColour 0xFFFF #define unusedColour 0x0000 #define emptyColour (16<<10) + (16<<5) +(16) #define hasDataColour (0<<10) + (31<<5) +(0) #define readColour (31<<10) + (31<<5) +(0) #define writeColour (0<<10) + (31<<5) +(31) #define collisionColour (31<<10) + (0<<5) +(0) static void BlitBufferGraph(DeviceDescriptionPtr ddp) { short * line0Ptr = nil; short * line00Ptr = nil; short * line1Ptr = nil; short * line2Ptr = nil; short * line3Ptr = nil; short buffCol = 0; long flags =0; int x,i,read,write; if (ddp->fPixDepth != 16 || ddp->fScreenBaseAddr ==0 || ddp->fRowBytes ==0) return; line00Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*18-ddp->fRowBytes/4); line0Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*19-ddp->fRowBytes/4); line1Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*16-ddp->fRowBytes/4); line2Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*17-ddp->fRowBytes/4); line3Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*15-ddp->fRowBytes/4); read = ddp->fSharedVars->fReader % ddp->fNumOutputFrames; write = ddp->fSharedVars->fWriter % ddp->fNumOutputFrames; for(x =0;x < ddp->fNumOutputFrames; x++) { *line1Ptr++ = (short)spacerColour; *line2Ptr++ = (short)spacerColour; *line0Ptr++ = (short)spacerColour; *line00Ptr++ = (short)spacerColour; for(i=0;ifBufferLocks[x];i++) { short* beardPtr = line0Ptr+ddp->fRowBytes*i*2; *beardPtr++ = unusedColour; *beardPtr++ = unusedColour; *beardPtr++ = unusedColour; *beardPtr++ = unusedColour; } if (ddp->fBufferLocks[x]) { buffCol = hasDataColour; } else { buffCol = emptyColour; } *line1Ptr++ = buffCol; *line1Ptr++ = buffCol; *line1Ptr++ = buffCol; *line1Ptr++ = buffCol; *line2Ptr++ = buffCol; *line2Ptr++ = buffCol; *line2Ptr++ = buffCol; *line2Ptr++ = buffCol; buffCol = (short)spacerColour; if (read == x) buffCol = readColour; if (write == x) { if (buffCol == readColour) buffCol = collisionColour; else buffCol = writeColour; } *line00Ptr++ = buffCol; *line00Ptr++ = buffCol; *line00Ptr++ = buffCol; *line00Ptr++ = buffCol; *line0Ptr++ = buffCol; *line0Ptr++ = buffCol; *line0Ptr++ = buffCol; *line0Ptr++ = buffCol; } } #endif