void CAHALAudioDevice::DestroyIOProcID(AudioDeviceIOProcID inIOProcID) { OSStatus theError = AudioDeviceDestroyIOProcID(mObjectID, inIOProcID); ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::DestroyIOProcID: got an error destroying the IOProc ID"); }
void CAHALAudioDevice::GetCurrentTime(AudioTimeStamp& outTime) { OSStatus theError = AudioDeviceGetCurrentTime(mObjectID, &outTime); ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::GetCurrentTime: got an error getting the current time"); }
void CAHALAudioDevice::TranslateTime(const AudioTimeStamp& inTime, AudioTimeStamp& outTime) { OSStatus theError = AudioDeviceTranslateTime(mObjectID, &inTime, &outTime); ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::TranslateTime: got an error translating time"); }
void HLAudioFile::GetFormat(AudioStreamBasicDescription& outFormat) const { ThrowIf(!mPrepared, CAException(fnOpnErr), "HLAudioFile::GetFormat: file hasn't been prepared yet"); outFormat = mFormat; }
void CAHALAudioDevice::StopIOProc(AudioDeviceIOProcID inIOProcID) { OSStatus theError = AudioDeviceStop(mObjectID, inIOProcID); ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StopIOProc: got an error stopping an IOProc"); }
void HLAudioFile::SetRawByteSize(SInt64 inSize) { // can't touch this file outside of the AudioFile API DebugMessage("HLAudioFile::SetRawByteSize: can't do that"); throw CAException(paramErr); }
void HLAudioFile::WriteRawBytes(SInt64 inOffset, UInt32& ioNumberBytes, void* inData, bool inCache) { // can't touch this file outside of the AudioFile API DebugMessage("HLAudioFile::WriteRawBytes: can't do that"); throw CAException(paramErr); }
void HLFileSystemObject::SetNameExtension(CFStringRef inNameExtension) { // the FSRef for a file can change after renaming, // so don't allow it to be done while the file is open ThrowIf(IsOpenForReading() || IsOpenForWriting(), CAException(fBsyErr), "HLFileSystemObject::SetNameExtension: can't change the file name extension of an open file"); // make a raw unicode string out of the CFString containing the new extension CACFString theExtension(inNameExtension, false); UInt32 theExtensionLength = 255; UniChar theExtensionString[255]; theExtension.GetUnicodeString(theExtensionString, theExtensionLength); // get the file name from the catalog info HFSUniStr255 theNameString; OSStatus theError = FSGetCatalogInfo(&mFSRef, kFSCatInfoNone, NULL, &theNameString, NULL, NULL); ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetNameExtension: couldn't get the catalog information"); // use Launch Services to find the start of the extension UniCharCount theExtensionStart = 0; LSGetExtensionInfo(theNameString.length, theNameString.unicode, &theExtensionStart); UInt32 theCharsToCopy; if(theExtensionStart != kLSInvalidExtensionIndex) { // there already was an extension, so replace it // figure out how many characters worth of extension can fit theCharsToCopy = 255UL - theExtensionStart; // range it against the actual length of the extension theCharsToCopy = theExtensionLength < theCharsToCopy ? theExtensionLength : theCharsToCopy; // copy the extension memcpy(&theNameString.unicode[theExtensionStart], theExtensionString, theCharsToCopy * sizeof(UniChar)); // update the length of the name string theNameString.length = theExtensionStart + theCharsToCopy; // save off the current FSRef, since it may change FSRef theOldFSRef; memcpy(&theOldFSRef, &mFSRef, sizeof(FSRef)); // rename the file, getting us the new FSRef theError = FSRenameUnicode(&theOldFSRef, theNameString.length, theNameString.unicode, kTextEncodingUnknown, &mFSRef); ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetName: couldn't rename the file"); } else if(theNameString.length < 254) { // there isn't an extension yet, and there's room for at least two characters // make a raw unicode string with the period CFRange thePeriodRange = { 0, 1 }; UniChar thePeriodString[255]; CFStringGetCharacters(HLFileSystemCFStringConstants::sNameExtensionDelimiter, thePeriodRange, thePeriodString); // copy it at the end of the string theNameString.unicode[theNameString.length] = thePeriodString[0]; // update the length theNameString.length += 1; // figure out how many characters worth of extension can fit theCharsToCopy = 255UL - theNameString.length; // range it against the actual length of the extension theCharsToCopy = theExtensionLength < theCharsToCopy ? theExtensionLength : theCharsToCopy; // copy the extension memcpy(&theNameString.unicode[theNameString.length], theExtensionString, theCharsToCopy * sizeof(UniChar)); // update the length of the name string theNameString.length += theCharsToCopy; // save off the current FSRef, since it may change FSRef theOldFSRef; memcpy(&theOldFSRef, &mFSRef, sizeof(FSRef)); // rename the file, getting us the new FSRef theError = FSRenameUnicode(&theOldFSRef, theNameString.length, theNameString.unicode, kTextEncodingUnknown, &mFSRef); ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetName: couldn't rename the file"); } }
void HLFileSystemObject::GetParentFSRef(FSRef& outFSRef) const { OSStatus theError = FSGetCatalogInfo(&mFSRef, kFSCatInfoNone, NULL, NULL, NULL, &outFSRef); ThrowIfError(theError, CAException(theError), "HLFileSystemObject::GetParentFSRef: couldn't get the catalog info"); }
bool CAGuard::WaitFor(UInt64 inNanos) { bool theAnswer = false; #if TARGET_OS_MAC ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait"); #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos); #endif struct timespec theTimeSpec; static const UInt64 kNanosPerSecond = 1000000000ULL; if(inNanos >= kNanosPerSecond) { theTimeSpec.tv_sec = static_cast<UInt32>(inNanos / kNanosPerSecond); theTimeSpec.tv_nsec = static_cast<UInt32>(inNanos % kNanosPerSecond); } else { theTimeSpec.tv_sec = 0; theTimeSpec.tv_nsec = static_cast<UInt32>(inNanos); } #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif mOwner = 0; #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::WaitFor: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif OSStatus theError = pthread_cond_timedwait_relative_np(&mCondVar, &mMutex, &theTimeSpec); ThrowIf((theError != 0) && (theError != ETIMEDOUT), CAException(theError), "CAGuard::WaitFor: Wait got an error"); mOwner = pthread_self(); #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos)); #endif #if Log_Latency DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos)); #endif #if Log_Average_Latency ++mAverageLatencyCount; mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos; if(mAverageLatencyCount >= 50) { DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount); mAverageLatencyCount = 0; mAverageLatencyAccumulator = 0.0; } #endif #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::WaitFor: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif theAnswer = theError == ETIMEDOUT; #elif TARGET_OS_WIN32 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait"); #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos); #endif // the time out is specified in milliseconds(!) UInt32 theWaitTime = static_cast<UInt32>(inNanos / 1000000ULL); #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif mOwner = 0; #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::WaitFor: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif ReleaseMutex(mMutex); HANDLE theHandles[] = { mMutex, mEvent }; OSStatus theError = WaitForMultipleObjects(2, theHandles, true, theWaitTime); ThrowIf((theError != WAIT_OBJECT_0) && (theError != WAIT_TIMEOUT), CAException(GetLastError()), "CAGuard::WaitFor: Wait got an error"); mOwner = GetCurrentThreadId(); ResetEvent(mEvent); #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos)); #endif #if Log_Latency DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos)); #endif #if Log_Average_Latency ++mAverageLatencyCount; mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos; if(mAverageLatencyCount >= 50) { DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount); mAverageLatencyCount = 0; mAverageLatencyAccumulator = 0.0; } #endif #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::WaitFor: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif theAnswer = theError == WAIT_TIMEOUT; #endif return theAnswer; }
bool CAMutex::Try(bool& outWasLocked) { bool theAnswer = false; outWasLocked = false; #if TARGET_OS_MAC pthread_t theCurrentThread = pthread_self(); if(!pthread_equal(theCurrentThread, mOwner)) { // this means the current thread doesn't already own the lock #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); #endif // go ahead and call trylock to see if we can lock it. int theError = pthread_mutex_trylock(&mMutex); if(theError == 0) { // return value of 0 means we successfully locked the lock mOwner = theCurrentThread; theAnswer = true; outWasLocked = true; #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); #endif } else if(theError == EBUSY) { // return value of EBUSY means that the lock was already locked by another thread theAnswer = false; outWasLocked = false; #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); #endif } else { // any other return value means something really bad happenned ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed"); } } else { // this means the current thread already owns the lock theAnswer = true; outWasLocked = false; } #elif TARGET_OS_WIN32 if(mOwner != GetCurrentThreadId()) { // this means the current thread doesn't own the lock #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif // try to acquire the mutex OSStatus theError = WaitForSingleObject(mMutex, 0); if(theError == WAIT_OBJECT_0) { // this means we successfully locked the lock mOwner = GetCurrentThreadId(); theAnswer = true; outWasLocked = true; #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif } else if(theError == WAIT_TIMEOUT) { // this means that the lock was already locked by another thread theAnswer = false; outWasLocked = false; #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif } else { // any other return value means something really bad happenned ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed"); } } else { // this means the current thread already owns the lock theAnswer = true; outWasLocked = false; } #endif return theAnswer; }
void SDP_PlugIn::DeviceSetPropertyData(UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData) { switch(inPropertyID) { case kSampleDriverPlugInDevicePropertyFoo: { // make sure the size is right ThrowIf(inPropertyDataSize != DeviceGetPropertyDataSize(inChannel, isInput, inPropertyID), CAException(kAudioHardwareBadPropertySizeError), "SDP_PlugIn::DeviceSetPropertyData: wrong data size for kSampleDriverPlugInDevicePropertyFoo"); // get the new value UInt32 theValue = *static_cast<const UInt32*>(inPropertyData); // tell the driver about it SetFoo(mHostInfo.mIOAudioEngine, theValue); } break; default: HP_DriverPlugIn::DeviceSetPropertyData(inChannel, isInput, inPropertyID, inPropertyDataSize, inPropertyData); break; }; }
void SDP_PlugIn::DeviceGetPropertyData(UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData) const { switch(inPropertyID) { case kSampleDriverPlugInDevicePropertyFoo: { // make sure the size is right ThrowIf(ioPropertyDataSize != DeviceGetPropertyDataSize(inChannel, isInput, inPropertyID), CAException(kAudioHardwareBadPropertySizeError), "SDP_PlugIn::DeviceGetPropertyData: wrong data size for kSampleDriverPlugInDevicePropertyFoo"); // set the return value *((UInt32*)outPropertyData) = GetFoo(mHostInfo.mIOAudioEngine); } break; default: HP_DriverPlugIn::DeviceGetPropertyData(inChannel, isInput, inPropertyID, ioPropertyDataSize, outPropertyData); break; }; }
void SHP_PlugIn::GetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32& ioDataSize, void* outData) const { switch(inAddress.mSelector) { case kAudioObjectPropertyName: ThrowIf(ioDataSize != GetPropertyDataSize(inAddress, inQualifierDataSize, inQualifierData), CAException(kAudioHardwareBadPropertySizeError), "SHP_PlugIn::GetPropertyData: wrong data size for kAudioObjectPropertyName"); *static_cast<CFStringRef*>(outData) = CFSTR("com.apple.audio.SampleHardwarePlugIn"); CFRetain(*static_cast<CFStringRef*>(outData)); break; default: HP_HardwarePlugIn::GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData); break; }; }