Ejemplo n.º 1
0
static void AQTestBufferCallback(void *					inUserData,
								AudioQueueRef			inAQ,
								AudioQueueBufferRef		inCompleteAQBuffer) 
{
	AQTestInfo * myInfo = (AQTestInfo *)inUserData;
	if (myInfo->mDone) return;
		
	UInt32 numBytes;
	UInt32 nPackets = myInfo->mNumPacketsToRead;

	OSStatus result = AudioFileReadPackets(myInfo->mAudioFile, false, &numBytes, myInfo->mPacketDescs, myInfo->mCurrentPacket, &nPackets, 
								inCompleteAQBuffer->mAudioData);
	if (result) {
		DebugMessageN1 ("Error reading from file: %d\n", (int)result);
		exit(1);
	}
	
	if (nPackets > 0) {
		inCompleteAQBuffer->mAudioDataByteSize = numBytes;		

		AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, (myInfo->mPacketDescs ? nPackets : 0), myInfo->mPacketDescs);
		
		myInfo->mCurrentPacket += nPackets;
	} else {
		result = AudioQueueStop(myInfo->mQueue, false);
		if (result) {
			DebugMessageN1 ("AudioQueueStop(false) failed: %d", (int)result);
			exit(1);
		}
			// reading nPackets == 0 is our EOF condition
		myInfo->mDone = true;
	}
}
Ejemplo n.º 2
0
void	CAHALAudioSystemObject::LogBasicDeviceInfo()
{
	UInt32 theNumberDevices = GetNumberAudioDevices();
	CAAutoArrayDelete<AudioObjectID> theDeviceList(theNumberDevices);
	GetAudioDevices(theNumberDevices, theDeviceList);
	DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: %d devices", (int)theNumberDevices);
	for(UInt32 theDeviceIndex = 0; theDeviceIndex < theNumberDevices; ++theDeviceIndex)
	{
		char theCString[256];
		UInt32 theCStringSize = sizeof(theCString);
		DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: Device %d", (int)theDeviceIndex);
		
		CAHALAudioDevice theDevice(theDeviceList[theDeviceIndex]);
		DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo:   Object ID: %d", (int)theDeviceList[theDeviceIndex]);
		
		CACFString theDeviceName(theDevice.CopyName());
		theCStringSize = sizeof(theCString);
		theDeviceName.GetCString(theCString, theCStringSize);
		DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo:   Name:      %s", theCString);
		
		CACFString theDeviceUID(theDevice.CopyDeviceUID());
		theCStringSize = sizeof(theCString);
		theDeviceUID.GetCString(theCString, theCStringSize);
		DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo:   UID:       %s", theCString);
	}
}
Ejemplo n.º 3
0
static void AQTestBufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) 
{
	AQTestInfo * myInfo = (AQTestInfo *)inUserData;
	if (myInfo->mDone) return;
		
	UInt32 numBytes;
	UInt32 nPackets = myInfo->mNumPacketsToRead;
	OSStatus result = AudioFileReadPackets(myInfo->mAudioFile,      // The audio file from which packets of audio data are to be read.
                                           false,                   // Set to true to cache the data. Otherwise, set to false.
                                           &numBytes,               // On output, a pointer to the number of bytes actually returned.
                                           myInfo->mPacketDescs,    // A pointer to an array of packet descriptions that have been allocated.
                                           myInfo->mCurrentPacket,  // The packet index of the first packet you want to be returned.
                                           &nPackets,               // On input, a pointer to the number of packets to read. On output, the number of packets actually read.
                                           inCompleteAQBuffer->mAudioData); // A pointer to user-allocated memory.
	if (result) {
		DebugMessageN1 ("Error reading from file: %d\n", (int)result);
		exit(1);
	}
    
    // we have some data
	if (nPackets > 0) {
		inCompleteAQBuffer->mAudioDataByteSize = numBytes;
        
		result = AudioQueueEnqueueBuffer(inAQ,                                  // The audio queue that owns the audio queue buffer.
                                         inCompleteAQBuffer,                    // The audio queue buffer to add to the buffer queue.
                                         (myInfo->mPacketDescs ? nPackets : 0), // The number of packets of audio data in the inBuffer parameter. See Docs.
                                         myInfo->mPacketDescs);                 // An array of packet descriptions. Or NULL. See Docs.
		if (result) {
			DebugMessageN1 ("Error enqueuing buffer: %d\n", (int)result);
			exit(1);
		}
        
		myInfo->mCurrentPacket += nPackets;
        
	} else {
        // **** This ensures that we flush the queue when done -- ensures you get all the data out ****
		
        if (!myInfo->mFlushed) {
			result = AudioQueueFlush(myInfo->mQueue);
			
            if (result) {
				DebugMessageN1("AudioQueueFlush failed: %d", (int)result);
				exit(1);
			}
            
			myInfo->mFlushed = true;
		}
		
		result = AudioQueueStop(myInfo->mQueue, false);
		if (result) {
			DebugMessageN1("AudioQueueStop(false) failed: %d", (int)result);
			exit(1);
		}
        
		// reading nPackets == 0 is our EOF condition
		myInfo->mDone = true;
	}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool	OALBuffer::UseThisBuffer(OALSource*	inSource)
{
#if LOG_VERBOSE
	DebugMessageN1("OALBuffer::UseThisBuffer() - OALBuffer = %ld", (long int) mSelfToken);
#endif
#if USE_SOURCE_LIST_MUTEX
	bool wasLocked = mSourceListGuard.Lock();
#endif
	
	// see if this source is in list already
	if (mAttachedSourceList->SourceExists(inSource) == true)
		mAttachedSourceList->IncreaseAttachmentCount(inSource);
	else
	{
		SourceAttachedInfo		nuSourceInfo;
		
		nuSourceInfo.mSource = inSource;
		nuSourceInfo.mAttachedCount = 1;
		
		mAttachedSourceList->Add(nuSourceInfo);
	}

#if USE_SOURCE_LIST_MUTEX
	if (wasLocked) mSourceListGuard.Unlock();
#endif
	
#if LOG_EXTRAS		
	DebugMessageN2("OALBuffer::UseThisBuffer - BufferToken:SourceToken = %ld:%ld", (long int)mSelfToken, (long int)inSource->GetToken());
#endif
	
	return noErr;
}
Ejemplo n.º 5
0
void	ZKMORHP_IOThreadSlave::WorkLoopTeardown()
{
	// The other thread holds the lock during teardown
	try {
		mWorkLoopPhase = kTeardownPhase;
		mDevice->GetIOCycleTelemetry().IOCycleTeardownBegin(mIOCycleCounter);

		//	the work loop has finished, clear the time constraints
		ClearTimeConstraints();
		
		//	tell the device that the IO thread is torn down
		mDevice->StopIOCycleTimingServices();
	}
	catch(const CAException& inException)
	{
		DebugMessageN1("ZKMORHP_IOThreadSlave::WorkLoopTeardown: Caught a CAException, code == %ld", (long int)inException.GetError());
	}
	catch(...)
	{
		DebugMessage("ZKMORHP_IOThreadSlave::WorkLoopTeardown: Caught an unknown exception.");
	}
	
	//	set the device state to know the engine has stopped
	mDevice->IOEngineStopped();
		
	//	Notify clients that the IO thread is stopping
	CAPropertyAddress theIsRunningAddress(kAudioDevicePropertyDeviceIsRunning);
	mDevice->PropertiesChanged(1, &theIsRunningAddress);

	mDevice->GetIOCycleTelemetry().IOCycleTeardownEnd(mIOCycleCounter);
	mWorkLoopPhase = kNotRunningPhase;
	mIOGuard.NotifyAll();
	mIOCycleCounter = 0;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus	OALBuffer::AddAudioDataStatic(char*	inAudioData, UInt32	inAudioDataSize, ALenum format, ALsizei freq)
{
#if LOG_VERBOSE
	DebugMessageN5("OALBuffer::AddAudioDataStatic() - OALBuffer:inAudioData:inAudioDataSize:format:freq = %ld:%p:%ld:%d:%d", (long int) mSelfToken, inAudioData, (long int) inAudioDataSize, format, freq);
#endif
    #if LOG_EXTRAS		
        DebugMessage("AddAudioDataStatic called: Converting Data Now");
    #endif

	CAGuard::Locker bufferLock(mBufferLock);

	try {
        
		if (!IsFormatSupported(format))
           throw ((OSStatus) AL_INVALID_VALUE);   // this is not a valid buffer token or is an invalid format
	
		// don't allow if the buffer is in a queue
        if (mAttachedSourceList->Size() > 0)
        {
            DebugMessage("AddAudioDataStatic ATTACHMENT > 0");
            throw ((OSStatus) AL_INVALID_OPERATION);   
        }
		
        mPreConvertedDataSize = (UInt32) inAudioDataSize;
        OSStatus    result = noErr;
		
		// if this buffer was using memory created by the library, free it now and initialize mData
		if (!mAppOwnsBufferMemory && (mData != NULL))
		{
			free (mData);
			mData = NULL;
		}
		
		mData = (UInt8*) inAudioData;
		mDataSize = (UInt32) inAudioDataSize;
				
		result = FillInASBD(mDataFormat, format, freq);
			THROW_RESULT
			
		mPreConvertedDataFormat.SetFrom(mDataFormat); //  make sure they are the same so original format info can be returned to caller
    }
    catch (OSStatus     result) {
		mData = NULL;
		mAppOwnsBufferMemory = false;
		DebugMessageN1("AddAudioDataStatic Failed - err = %ld\n", (long int) result);
        alSetError(result);
    }
    catch (...) {
		mData = NULL;
		mAppOwnsBufferMemory = false;
		DebugMessage("AddAudioDataStatic Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	mAppOwnsBufferMemory = true;
	return noErr;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UInt32		OALBuffer::GetFrameCount()
{
#if LOG_VERBOSE
	DebugMessageN1("OALBuffer::GetFrameCount() - OALBuffer = %ld", (long int) mSelfToken);
#endif
	UInt32	totalPackets =  (mDataFormat.mBytesPerPacket == 0) ? 0 : mDataSize/mDataFormat.mBytesPerPacket;
	
	return totalPackets * mDataFormat.mFramesPerPacket;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OALBuffer::~OALBuffer()
{
#if LOG_VERBOSE
	DebugMessageN1("OALBuffer::~OALBuffer() - OALBuffer = %ld", (long int) mSelfToken);
#endif
	if (!mAppOwnsBufferMemory && (mData != NULL))
		free (mData);
		
// should never be deleted unless this object said it was ok
#if USE_SOURCE_LIST_MUTEX
	bool wasLocked = mSourceListGuard.Lock();
#endif

	if (mAttachedSourceList)
		delete mAttachedSourceList;

#if USE_SOURCE_LIST_MUTEX
	if (wasLocked) mSourceListGuard.Unlock();
#endif
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool	OALBuffer::IsPurgable()
{
#if LOG_VERBOSE
	DebugMessageN1("OALBuffer::IsPurgable() - OALBuffer = %ld", (long int) mSelfToken);
#endif
	bool returnValue = false;
	
#if USE_SOURCE_LIST_MUTEX
	bool wasLocked = mSourceListGuard.Lock();
#endif
	
	// make sure that no other source has attached this buffer, and that no other thread is editing it
	if ((mAttachedSourceList->Size() == 0) && mBufferLock.IsFree() && (mInUseFlag <= 0) && (!IsInPostRenderMessageQueue()))
		returnValue = true; 
	
#if USE_SOURCE_LIST_MUTEX
	if (wasLocked) mSourceListGuard.Unlock();
#endif

	return returnValue;
}
OALBuffer::OALBuffer (ALuint	inSelfToken)
	: 	mSelfToken (inSelfToken),
#if USE_SOURCE_LIST_MUTEX
		mSourceListGuard ("OALBuffer::SourceListGuard"),
#endif
		mBufferLock ("OALBuffer::EditLock"),
		mInUseFlag(0),
		mData(NULL),
		mAppOwnsBufferMemory(false),
		mDataSize (0),
		mPreConvertedDataSize(0),
		mDataHasBeenConverted(false),
		mAttachedSourceList(NULL),
        mIsInPostRenderMessageQueue(false)
{
#if LOG_VERBOSE
	DebugMessageN1("OALBuffer::OALBuffer() - OALBuffer = %ld", (long int) mSelfToken);
#endif
	mAttachedSourceList = new AttachedSourceList ();			// create a source list map
	mAttachedSourceList->Reserve(128);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool		OALBuffer::CanBeRemovedFromBufferMap()
{
#if LOG_VERBOSE
	DebugMessageN1("OALBuffer::CanBeRemovedFromBufferMap() - OALBuffer = %ld", (long int) mSelfToken);
#endif
	bool	returnValue = true;
	
#if USE_SOURCE_LIST_MUTEX
	bool wasLocked = mSourceListGuard.Lock();
#endif

	// if the buffer object is not attached to a source, it's ok to remove
	if (mAttachedSourceList->Size() == 0)
		returnValue = true;
	else
	{
		// if all attached sources are transitioning to flush, it can be removed from buffer map,
		// but the OALBuffer object must be deleted at a later time
		for (UInt32	i = 0; i < mAttachedSourceList->Size(); i++)
		{
			OALSource	*curSource = mAttachedSourceList->GetSourceByIndex(i);
			if (curSource)
			{
				if (!curSource->IsSourceTransitioningToFlushQ())
				{
					returnValue = false; 
					goto Finished;
				}
			}
		}
	}
	
Finished:

#if USE_SOURCE_LIST_MUTEX
	if (wasLocked) mSourceListGuard.Unlock();
#endif

	return returnValue; // all attached sources are transitioning to flush
}								
Ejemplo n.º 12
0
void	CAHostTimeBase::Initialize()
{
	//	get the info about Absolute time
	#if TARGET_OS_MAC
		struct mach_timebase_info	theTimeBaseInfo;
		mach_timebase_info(&theTimeBaseInfo);
		sMinDelta = 1;
		sToNanosNumerator = theTimeBaseInfo.numer;
		sToNanosDenominator = theTimeBaseInfo.denom;
		sFromNanosNumerator = sToNanosDenominator;
		sFromNanosDenominator = sToNanosNumerator;

		//	the frequency of that clock is: (sToNanosDenominator / sToNanosNumerator) * 10^9
		sFrequency = static_cast<Float64>(sToNanosDenominator) / static_cast<Float64>(sToNanosNumerator);
		sFrequency *= 1000000000.0;
	#elif TARGET_OS_WIN32
		LARGE_INTEGER theFrequency;
		QueryPerformanceFrequency(&theFrequency);
		sMinDelta = 1;
		sToNanosNumerator = 1000000000ULL;
		sToNanosDenominator = *((UInt64*)&theFrequency);
		sFromNanosNumerator = sToNanosDenominator;
		sFromNanosDenominator = sToNanosNumerator;
		sFrequency = static_cast<Float64>(*((UInt64*)&theFrequency));
	#endif
	sInverseFrequency = 1.0 / sFrequency;
	
	#if	Log_Host_Time_Base_Parameters
		DebugMessage(  "Host Time Base Parameters");
		DebugMessageN1(" Minimum Delta:          %lu", sMinDelta);
		DebugMessageN1(" Frequency:              %f", sFrequency);
		DebugMessageN1(" To Nanos Numerator:     %lu", sToNanosNumerator);
		DebugMessageN1(" To Nanos Denominator:   %lu", sToNanosDenominator);
		DebugMessageN1(" From Nanos Numerator:   %lu", sFromNanosNumerator);
		DebugMessageN1(" From Nanos Denominator: %lu", sFromNanosDenominator);
	#endif

	sIsInited = true;
}
Ejemplo n.º 13
0
IOReturn AREngine::clipOutputSamples(const void* inMixBuffer, void* outTargetBuffer, UInt32 inFirstFrame, UInt32 inNumberFrames, const IOAudioStreamFormat* inFormat, IOAudioStream* /*inStream*/)
{
	//	figure out what sort of blit we need to do
	if((inFormat->fSampleFormat == kIOAudioStreamSampleFormatLinearPCM) && inFormat->fIsMixable)
	{
		//	it's mixable linear PCM, which means we will be calling a blitter, which works in samples not frames
		Float32* theMixBuffer = (Float32*)inMixBuffer;
		UInt32 theFirstSample = inFirstFrame * inFormat->fNumChannels;
		UInt32 theNumberSamples = inNumberFrames * inFormat->fNumChannels;
	
		if(inFormat->fNumericRepresentation == kIOAudioStreamNumericRepresentationSignedInt)
		{
			//	it's some kind of signed integer, which we handle as some kind of even byte length
			bool nativeEndianInts;
			#if TARGET_RT_BIG_ENDIAN
				nativeEndianInts = (inFormat->fByteOrder == kIOAudioStreamByteOrderBigEndian);
			#else
				nativeEndianInts = (inFormat->fByteOrder == kIOAudioStreamByteOrderLittleEndian);
			#endif
			
			switch(inFormat->fBitWidth)
			{
				case 8:
					{
						DebugMessage("AREngine::clipOutputSamples: can't handle signed integers with a bit width of 8 at the moment");
					}
					break;
				
				case 16:
					{
						SInt16* theTargetBuffer = (SInt16*)outTargetBuffer;
						if (nativeEndianInts)
							Float32ToNativeInt16(mHasVectorUnit, &(theMixBuffer[theFirstSample]), &(theTargetBuffer[theFirstSample]), theNumberSamples);
						else
							Float32ToSwapInt16(mHasVectorUnit, &(theMixBuffer[theFirstSample]), &(theTargetBuffer[theFirstSample]), theNumberSamples);
					}
					break;
				
				case 24:
					{
						UInt8* theTargetBuffer = (UInt8*)outTargetBuffer;
						if (nativeEndianInts)
							Float32ToNativeInt24(mHasVectorUnit, &(theMixBuffer[theFirstSample]), &(theTargetBuffer[3*theFirstSample]), theNumberSamples);
						else
							Float32ToSwapInt24(mHasVectorUnit, &(theMixBuffer[theFirstSample]), &(theTargetBuffer[3*theFirstSample]), theNumberSamples);
					}
					break;
				
				case 32:
					{
						SInt32* theTargetBuffer = (SInt32*)outTargetBuffer;
						if (nativeEndianInts)
							Float32ToNativeInt32(mHasVectorUnit, &(theMixBuffer[theFirstSample]), &(theTargetBuffer[theFirstSample]), theNumberSamples);
						else
							Float32ToSwapInt32(mHasVectorUnit, &(theMixBuffer[theFirstSample]), &(theTargetBuffer[theFirstSample]), theNumberSamples);
					}
					break;
				
				default:
					DebugMessageN1("AREngine::clipOutputSamples: can't handle signed integers with a bit width of %d", inFormat->fBitWidth);
					break;
				
			}
		}
		else if(inFormat->fNumericRepresentation == kIOAudioStreamNumericRepresentationIEEE754Float)
		{
			//	it is some kind of floating point format
		#if TARGET_RT_BIG_ENDIAN
			if((inFormat->fBitWidth == 32) && (inFormat->fBitDepth == 32) && (inFormat->fByteOrder == kIOAudioStreamByteOrderBigEndian))
		#else
			if((inFormat->fBitWidth == 32) && (inFormat->fBitDepth == 32) && (inFormat->fByteOrder == kIOAudioStreamByteOrderLittleEndian))
		#endif
			{
				//	it's Float32, so we are just going to copy the data
				Float32* theTargetBuffer = (Float32*)outTargetBuffer;
				memcpy(&(theTargetBuffer[theFirstSample]), &(theMixBuffer[theFirstSample]), theNumberSamples * sizeof(Float32));
			}
			else
			{
				DebugMessageN2("AREngine::clipOutputSamples: can't handle floats with a bit width of %d, bit depth of %d, and/or the given byte order", inFormat->fBitWidth, inFormat->fBitDepth);
			}
		}
	}
	else
	{
		//	it's not linear PCM or it's not mixable, so just copy the data into the target buffer
		SInt8* theMixBuffer = (SInt8*)inMixBuffer;
		SInt8* theTargetBuffer = (SInt8*)outTargetBuffer;
		UInt32 theFirstByte = inFirstFrame * (inFormat->fBitWidth / 8) * inFormat->fNumChannels;
		UInt32 theNumberBytes = inNumberFrames * (inFormat->fBitWidth / 8) * inFormat->fNumChannels;
		memcpy(&(theTargetBuffer[theFirstByte]), &(theMixBuffer[theFirstByte]), theNumberBytes);
	}

	return kIOReturnSuccess;
}
Ejemplo n.º 14
0
bool	ZKMORHP_IOThreadSlave::WorkLoopInit()
{
	//	grab the IO guard
	bool wasLocked = mIOGuard.Lock();
	bool isInNeedOfResynch = false;

		//	initialize some stuff
	mWorkLoopPhase = kInitializingPhase;
	mIOCycleCounter = 0;
	mOverloadCounter = 0;
	CAPropertyAddress theIsRunningAddress(kAudioDevicePropertyDeviceIsRunning);
	mDevice->GetIOCycleTelemetry().IOCycleInitializeBegin(mIOCycleCounter);
	
	try {
	
		//	and signal that the IO thread is running
		mIOGuard.NotifyAll();
		
		//	initialize the work loop stopping conditions
		mStopWorkLoop = false;
		
		//	Tell the device that the IO thread has initialized. Note that we unlock around this call
		//	due to the fact that IOCycleInitialize might not return for a while because it might
		//	have to wait for the hardware to start.
		if(wasLocked)
		{
			mIOGuard.Unlock();
		}
		
		//	tell the device that the IO cycle is initializing to start the timing services
		mDevice->StartIOCycleTimingServices();
		
		//	set the device state to know the engine is running
		mDevice->IOEngineStarted();
		
		//	notify clients that the engine is running
		mDevice->PropertiesChanged(1, &theIsRunningAddress);
		
		//	re-lock the guard
		wasLocked = mIOGuard.Lock();

		//	make sure the thread is still running before moving on
		if(!mStopWorkLoop)
		{
			//	set the time constraints for the IOThread
			SetTimeConstraints();
			
			//	initialize the clock
			mDevice->EstablishIOCycleAnchorTime(mAnchorTime);
			mFrameCounter = 0;
			
#if	Offset_For_Input
			if(mDevice->HasInputStreams())
			{
				//	the first sleep cycle as to be at least the input safety offset and a buffer's
				//	worth of time to be sure that the input data is all there
				mFrameCounter += mDevice->GetSafetyOffset(true);
			}
#endif
			
			//	enter the work loop
			mWorkLoopPhase = kRunningPhase;
			isInNeedOfResynch = false;
			mDevice->GetIOCycleTelemetry().IOCycleInitializeEnd(mIOCycleCounter, mAnchorTime);
				// the work loop interation is called from another thread
//			while(!mStopWorkLoop)
//			{
//				WorkLoopIteration(isInNeedOfResynch, wasLocked);
//			}
			if (wasLocked) mIOGuard.Unlock();
		}
	}
	catch(const CAException& inException)
	{
		DebugMessageN1("ZKMORHP_IOThreadSlave::WorkLoopInit: Caught a CAException, code == %ld", (long int)inException.GetError());
	}
	catch(...)
	{
		DebugMessage("ZKMORHP_IOThreadSlave::WorkLoopInit: Caught an unknown exception.");
	}
	
	return isInNeedOfResynch;
}
Ejemplo n.º 15
0
void	HP_IOThread::WorkLoop()
{
	//	grab the IO guard
	bool wasLocked = mIOGuard.Lock();
	
	//	initialize some stuff
	mWorkLoopPhase = kInitializingPhase;
	mIOCycleCounter = 0;
	mOverloadCounter = 0;
	CAPropertyAddress theIsRunningAddress(kAudioDevicePropertyDeviceIsRunning);
#if Use_HAL_Telemetry
	mDevice->GetIOCycleTelemetry().IOCycleInitializeBegin(mIOCycleCounter);
#else
	HAL_IOCYCLEINITIALIZEBEGIN(mIOCycleCounter);
#endif
	try
	{
		//	and signal that the IO thread is running
		mIOGuard.NotifyAll();
		
		//	initialize the work loop stopping conditions
		mStopWorkLoop = false;
		
		//	Tell the device that the IO thread has initialized. Note that we unlock around this call
		//	due to the fact that IOCycleInitialize might not return for a while because it might
		//	have to wait for the hardware to start.
		if(wasLocked)
		{
			mIOGuard.Unlock();
		}
		
		//	tell the device that the IO cycle is initializing to start the timing services
		mDevice->StartIOCycleTimingServices();
		
		//	set the device state to know the engine is running
		mDevice->IOEngineStarted();
		
		//	notify clients that the engine is running
		mDevice->PropertiesChanged(1, &theIsRunningAddress);
		
		//	re-lock the guard
		wasLocked = mIOGuard.Lock();

		//	make sure the thread is still running before moving on
		if(!mStopWorkLoop)
		{
			//	set the time constraints for the IOThread
			SetTimeConstraints();
			
			//	initialize the clock
			mDevice->EstablishIOCycleAnchorTime(mAnchorTime);
			mFrameCounter = 0;
			
#if	Offset_For_Input
			if(mDevice->HasInputStreams())
			{
				//	the first sleep cycle as to be at least the input safety offset and a buffer's
				//	worth of time to be sure that the input data is all there
				mFrameCounter += mDevice->GetSafetyOffset(true);
			}
#endif
			
			//	get the current time
			AudioTimeStamp theCurrentTime;
			mDevice->GetCurrentTime(theCurrentTime);
				
			//	enter the work loop
			mWorkLoopPhase = kRunningPhase;
			bool isInNeedOfResynch = false;
			bool isCheckingForOverloads = false;
			Float64 theIOBufferFrameSize = mDevice->GetIOBufferFrameSize();
#if Use_HAL_Telemetry
			mDevice->GetIOCycleTelemetry().IOCycleInitializeEnd(mIOCycleCounter, mAnchorTime);
			mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime);
#else
			HAL_IOCYCLEINITIALIZEEND(mIOCycleCounter, mAnchorTime);
			HAL_IOCYCLEWORKLOOPBEGIN(mIOCycleCounter, theCurrentTime);
#endif
			while(!mStopWorkLoop)
			{
				//	get the new IO buffer frame size
				Float64 theNewIOBufferFrameSize = mDevice->GetIOBufferFrameSize();
				
				//	initialize the next wake up time
				AudioTimeStamp theNextWakeUpTime = CAAudioTimeStamp::kZero;
				theNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
				
				//	get the current time
				mDevice->GetCurrentTime(theCurrentTime);
				
				//	we have to run a special, untimed IO cycle if the IO buffer size changed
				if((theNewIOBufferFrameSize != theIOBufferFrameSize) && (theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter)))
				{
					//	mark the end of the previous cycle
#if Use_HAL_Telemetry
					mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime);
#else
					HAL_IOCYCLEWORKLOOPEND(mIOCycleCounter, theCurrentTime, theNextWakeUpTime);
#endif
					//	increment the cycle counter
					++mIOCycleCounter;
					
					//	increment the frame counter
					mFrameCounter += theIOBufferFrameSize;
				
					//	the new cycle is starting
#if Use_HAL_Telemetry
					mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime);
#else
					HAL_IOCYCLEWORKLOOPBEGIN(mIOCycleCounter, theCurrentTime);
#endif

					//	do the IO, note that we don't need to update the timing services for this special cycle
					isInNeedOfResynch = PerformIO(theCurrentTime, theIOBufferFrameSize);
					
					//	turn off overload checking for the next cycle to be nice to clients
					isCheckingForOverloads = false;
				}
				
				//	calculate the next wake up time
				if(CalculateNextWakeUpTime(theCurrentTime, theIOBufferFrameSize, theNextWakeUpTime, isCheckingForOverloads, isInNeedOfResynch, wasLocked))
				{
					//	sleep until the  next wake up time
#if Use_HAL_Telemetry
					mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime);
#else
					HAL_IOCYCLEWORKLOOPEND(mIOCycleCounter, theCurrentTime, theNextWakeUpTime);
#endif

					mIOGuard.WaitUntil(CAHostTimeBase::ConvertToNanos(theNextWakeUpTime.mHostTime));
					
					//	increment the cycle counter
					++mIOCycleCounter;
					
					//	make sure overload checking is enabled
					isCheckingForOverloads = true;
					
					//	do IO if the thread wasn't stopped
					if(!mStopWorkLoop)
					{
						//	get the current time
						mDevice->GetCurrentTime(theCurrentTime);
						
						if(theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter))
						{
							//	increment the frame counter
							mFrameCounter += theIOBufferFrameSize;
						
							//	refresh the current buffer size
							theIOBufferFrameSize = theNewIOBufferFrameSize;
							
							//	the new cycle is starting
#if Use_HAL_Telemetry
							mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime);
#else
							HAL_IOCYCLEWORKLOOPBEGIN(mIOCycleCounter, theCurrentTime);
#endif

							if(mDevice->UpdateIOCycleTimingServices())
							{
								//	something unexpected happenned with the time stamp, so resynch prior to doing IO
								AudioTimeStamp theNewAnchor = CAAudioTimeStamp::kZero;
								theNewAnchor.mSampleTime = 0;
								theNewAnchor.mHostTime = 0;
								theNewAnchor.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
								if(mDevice->EstablishIOCycleAnchorTime(theNewAnchor))
								{
									Resynch(&theNewAnchor, false);
								}
								else
								{
									Resynch(NULL, false);
								}
								
								//	re-get the current time too
								mDevice->GetCurrentTime(theCurrentTime);
								
								//	mark the telemetry
#if Use_HAL_Telemetry
								mDevice->GetIOCycleTelemetry().Resynch(GetIOCycleNumber(), mAnchorTime);
#else
								HAL_RESYNCH(GetIOCycleNumber(), mAnchorTime);
#endif
							}
						
							//	do the IO
							isInNeedOfResynch = PerformIO(theCurrentTime, theIOBufferFrameSize);
						}
					}
				}
				else
				{
					//	calculating the next wake up time failed, so we just stop everything (which
					//	will get picked up when the commands are executed
					mDevice->ClearAllCommands();
					mDevice->Do_StopAllIOProcs();
				}
				
				//	execute any deferred commands
				mDevice->ExecuteAllCommands();
			}
		}
	
		mWorkLoopPhase = kTeardownPhase;
#if Use_HAL_Telemetry
		mDevice->GetIOCycleTelemetry().IOCycleTeardownBegin(mIOCycleCounter);
#else
		HAL_IOCYCLETEARDOWNBEGIN(mIOCycleCounter);
#endif

		//	the work loop has finished, clear the time constraints
		ClearTimeConstraints();
		
		//	tell the device that the IO thread is torn down
		mDevice->StopIOCycleTimingServices();
	}
	catch(const CAException& inException)
	{
		DebugMessageN1("HP_IOThread::WorkLoop: Caught a CAException, code == %ld", (long int)inException.GetError());
	}
	catch(...)
	{
		DebugMessage("HP_IOThread::WorkLoop: Caught an unknown exception.");
	}
	
	//	set the device state to know the engine has stopped
	mDevice->IOEngineStopped();
		
	//	Notify clients that the IO thread is stopping. Note that we unlock around this call
	//	due to the fact that clients might want to call back into the HAL.
	if(wasLocked)
	{
		mIOGuard.Unlock();
	}

	//	Notify clients that the IO thread is stopping
	mDevice->PropertiesChanged(1, &theIsRunningAddress);
		
	//	re-lock the guard
	wasLocked = mIOGuard.Lock();

#if Use_HAL_Telemetry
	mDevice->GetIOCycleTelemetry().IOCycleTeardownEnd(mIOCycleCounter);
#else
	HAL_IOCYCLETEARDOWNEND(mIOCycleCounter);
#endif

	mWorkLoopPhase = kNotRunningPhase;
	mIOGuard.NotifyAll();
	mIOCycleCounter = 0;
	
	if(wasLocked)
	{
		mIOGuard.Unlock();
	}
}
Ejemplo n.º 16
0
void	ZKMORHP_IOThreadSlave::WorkLoopIteration(bool& isInNeedOfResynch)
{
	if (mStopWorkLoop) {
		WorkLoopTeardown();
		return;
	}
	
	try	{
		bool wasLocked = mIOGuard.Lock();
//		bool wasLocked;
		wasLocked = mIOGuard.Try(wasLocked);
		
		//	get the current time
		AudioTimeStamp theCurrentTime;
		mDevice->GetCurrentTime(theCurrentTime);
		
			//	increment the counter
			++mIOCycleCounter;
			
		//	do IO if the thread wasn't stopped
		if(!mStopWorkLoop)
		{
			if(theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter))
			{
				//	increment the frame counter
				mFrameCounter += mDevice->GetIOBufferFrameSize();
			
				//	the new cycle is starting
				mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime);
				if(mDevice->UpdateIOCycleTimingServices())
				{
					//	something unexpected happened with the time stamp, so resynch prior to doing IO
					AudioTimeStamp theNewAnchor = CAAudioTimeStamp::kZero;
					theNewAnchor.mSampleTime = 0;
					theNewAnchor.mHostTime = 0;
					theNewAnchor.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
					if(mDevice->EstablishIOCycleAnchorTime(theNewAnchor))
					{
						Resynch(&theNewAnchor, false);
					}
					else
					{
						Resynch(NULL, false);
					}
					
					//	re-get the current time too
					mDevice->GetCurrentTime(theCurrentTime);
				}
			
				//	do the IO
				isInNeedOfResynch = PerformIO(theCurrentTime);
			}
		}
		
		//	calculate the next wake up time
		AudioTimeStamp theNextWakeUpTime = CAAudioTimeStamp::kZero;
		theNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
//		bool wasLocked = false;
//		bool wasLocked = mIOGuard.Lock();
		if(CalculateNextWakeUpTime(theCurrentTime, theNextWakeUpTime, isInNeedOfResynch, wasLocked))
		{
			mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime);
		}
		
		//	execute any deferred commands
		mDevice->ExecuteAllCommands();
		if (wasLocked) mIOGuard.Unlock();
	} 
	catch(const CAException& inException)
	{
		DebugMessageN1("ZKMORHP_IOThreadSlave::WorkLoopIteration: Caught a CAException, code == %ld", (long int)inException.GetError());
	}
	catch(...)
	{
		DebugMessage("ZKMORHP_IOThreadSlave::WorkLoopIteration: Caught an unknown exception.");
	}
}
Ejemplo n.º 17
0
// _______________________________________________________________________________________
//
OSStatus CAAudioFile::ReadInputProc(	AudioConverterRef				inAudioConverter,
										UInt32*							ioNumberDataPackets,
										AudioBufferList*				ioData,
										AudioStreamPacketDescription**	outDataPacketDescription,
										void*							inUserData)
{
	CAAudioFile *This = static_cast<CAAudioFile *>(inUserData);

#if 0
	SInt64 remainingPacketsInFile = This->mNumberPackets - This->mPacketMark;
	if (remainingPacketsInFile <= 0) {
		*ioNumberDataPackets = 0;
		ioData->mBuffers[0].mDataByteSize = 0;
		if (outDataPacketDescription)
			*outDataPacketDescription = This->mPacketDescs;
#if VERBOSE_IO
		printf("CAAudioFile::ReadInputProc: EOF\n");
#endif
		return noErr;	// not eofErr; EOF is signified by 0 packets/0 bytes
	}
#endif

	// determine how much to read
	AudioBufferList *readBuffer;
	UInt32 readPackets;
	if (inAudioConverter != NULL) {
		// getting called from converter, need to use our I/O buffer
		readBuffer = &This->mIOBufferList;
		readPackets = This->mIOBufferSizePackets;
	} else {
		// getting called directly from ReadPackets, use supplied buffer
		if (This->mFileMaxPacketSize == 0)
			return kExtAudioFileError_MaxPacketSizeUnknown;
		readBuffer = ioData;
		readPackets = std::min(*ioNumberDataPackets, readBuffer->mBuffers[0].mDataByteSize / This->mFileMaxPacketSize);
			// don't attempt to read more packets than will fit in the buffer
	}
	// don't try to read past EOF
//	if (readPackets > remainingPacketsInFile)
//		readPackets = remainingPacketsInFile;
	// don't read more packets than necessary to produce the requested amount of converted data
	if (readPackets > This->mMaxPacketsToRead) {
#if VERBOSE_IO
		printf("CAAudioFile::ReadInputProc: limiting read to %ld packets (from %ld)\n", This->mMaxPacketsToRead, readPackets);
#endif
		readPackets = This->mMaxPacketsToRead;
	}

	// read
	UInt32 bytesRead;
	OSStatus err;

	StartTiming(This, read);
	StartTiming(This, readinconv);
	err = AudioFileReadPackets(This->mAudioFile, This->mUseCache, &bytesRead, This->mPacketDescs, This->mPacketMark, &readPackets, readBuffer->mBuffers[0].mData);
#if CAAUDIOFILE_PROFILE
	if (This->mInConverter) ElapsedTime(This, readinconv, This->mTicksInReadInConverter);
#endif
	ElapsedTime(This, read, This->mTicksInIO);

	if (err) {
		DebugMessageN1("Error %ld from AudioFileReadPackets!!!\n", err);
		return err;
	}

#if VERBOSE_IO
	printf("CAAudioFile::ReadInputProc: read %ld packets (%qd-%qd), %ld bytes, err %ld\n", readPackets, This->mPacketMark, This->mPacketMark + readPackets, bytesRead, err);
#if VERBOSE_IO >= 2
	if (This->mPacketDescs) {
		for (UInt32 i = 0; i < readPackets; ++i) {
			printf("  read packet %qd : offset %qd, length %ld\n", This->mPacketMark + i, This->mPacketDescs[i].mStartOffset, This->mPacketDescs[i].mDataByteSize);
		}
	}
	printf("  read buffer:"); CAShowAudioBufferList(readBuffer, 0, 4);
#endif
#endif
	if (readPackets == 0) {
		*ioNumberDataPackets = 0;
		ioData->mBuffers[0].mDataByteSize = 0;
		return noErr;
	}

	if (outDataPacketDescription)
		*outDataPacketDescription = This->mPacketDescs;
	ioData->mBuffers[0].mDataByteSize = bytesRead;
	ioData->mBuffers[0].mData = readBuffer->mBuffers[0].mData;

	This->mPacketMark += readPackets;
	if (This->mClientDataFormat.mFramesPerPacket != 1) {	// for PCM client formats we update in Read
		// but for non-PCM client format (weird case) we must update here/now
		if (This->mFileDataFormat.mFramesPerPacket > 0)
			This->mFrameMark += readPackets * This->mFileDataFormat.mFramesPerPacket;
		else {
			for (UInt32 i = 0; i < readPackets; ++i)
				This->mFrameMark += This->mPacketDescs[i].mVariableFramesInPacket;
		}
	}
	*ioNumberDataPackets = readPackets;
	return noErr;
}
Ejemplo n.º 18
0
bool	HP_Object::IsSubClass(AudioClassID inClassID, AudioClassID inBaseClassID)
{
	bool theAnswer = false;
	
	switch(inBaseClassID)
	{
		case kAudioObjectClassID:
		{
			//  all classes are subclasses of AudioObject
			theAnswer = true;
		}
		break;
		
		case kAudioControlClassID:
		{
			switch(inClassID)
			{
				case kAudioControlClassID:
				case kAudioLevelControlClassID:
				case kAudioBooleanControlClassID:
				case kAudioSelectorControlClassID:
				case kAudioStereoPanControlClassID:
				case kAudioVolumeControlClassID:
				case kAudioLFEVolumeControlClassID:
				case kAudioBootChimeVolumeControlClassID:
				case kAudioMuteControlClassID:
				case kAudioSoloControlClassID:
				case kAudioJackControlClassID:
				case kAudioLFEMuteControlClassID:
				case kAudioISubOwnerControlClassID:
				case kAudioDataSourceControlClassID:
				case kAudioDataDestinationControlClassID:
				case kAudioClockSourceControlClassID:
				case kAudioLineLevelControlClassID:
				{
					theAnswer = true;
				}
				break;
			};
		}
		break;
		
		case kAudioLevelControlClassID:
		{
			switch(inClassID)
			{
				case kAudioLevelControlClassID:
				case kAudioVolumeControlClassID:
				case kAudioLFEVolumeControlClassID:
				case kAudioBootChimeVolumeControlClassID:
				{
					theAnswer = true;
				}
				break;
			};
		}
		break;
		
		case kAudioBooleanControlClassID:
		{
			switch(inClassID)
			{
				case kAudioBooleanControlClassID:
				case kAudioMuteControlClassID:
				case kAudioSoloControlClassID:
				case kAudioJackControlClassID:
				case kAudioLFEMuteControlClassID:
				case kAudioISubOwnerControlClassID:
				{
					theAnswer = true;
				}
				break;
			};
		}
		break;
		
		case kAudioSelectorControlClassID:
		{
			switch(inClassID)
			{
				case kAudioSelectorControlClassID:
				case kAudioDataSourceControlClassID:
				case kAudioDataDestinationControlClassID:
				case kAudioClockSourceControlClassID:
				case kAudioLineLevelControlClassID:
				{
					theAnswer = true;
				}
				break;
			};
		}
		break;
		
		case kAudioDeviceClassID:
		{
			switch(inClassID)
			{
				case kAudioDeviceClassID:
				case kAudioAggregateDeviceClassID:
				{
					theAnswer = true;
				}
				break;
			};
		}
		break;
		
		//  leaf classes
		case kAudioStereoPanControlClassID:
		case kAudioVolumeControlClassID:
		case kAudioLFEVolumeControlClassID:
		case kAudioBootChimeVolumeControlClassID:
		case kAudioMuteControlClassID:
		case kAudioSoloControlClassID:
		case kAudioJackControlClassID:
		case kAudioLFEMuteControlClassID:
		case kAudioISubOwnerControlClassID:
		case kAudioDataSourceControlClassID:
		case kAudioDataDestinationControlClassID:
		case kAudioClockSourceControlClassID:
		case kAudioLineLevelControlClassID:
		case kAudioSystemObjectClassID:
		case kAudioPlugInClassID:
		case kAudioStreamClassID:
		case kAudioAggregateDeviceClassID:
		case kAudioSubDeviceClassID:
		{
			theAnswer = inClassID == inBaseClassID;
		}
		break;
		
		default:
		{
			#if CoreAudio_Debug
				char theClassIDString[5] = CA4CCToCString(inBaseClassID);
				DebugMessageN1("HP_Object::IsSubClass: unknown base class '%s'", theClassIDString);
			#endif
			theAnswer = inClassID == inBaseClassID;
		}
		break;
		
	};
	
	return theAnswer;
}
Ejemplo n.º 19
0
void	ZKMORHP_IOThreadSlave::WorkLoop()
{
	//	grab the IO guard
	bool wasLocked = mIOGuard.Lock();
	
	//	initialize some stuff
	mWorkLoopPhase = kInitializingPhase;
	mIOCycleCounter = 0;
	mOverloadCounter = 0;
	CAPropertyAddress theIsRunningAddress(kAudioDevicePropertyDeviceIsRunning);
	mDevice->GetIOCycleTelemetry().IOCycleInitializeBegin(mIOCycleCounter);
		
	try
	{
		//	and signal that the IO thread is running
		mIOGuard.NotifyAll();
		
		//	initialize the work loop stopping conditions
		mStopWorkLoop = false;
		
		//	Tell the device that the IO thread has initialized. Note that we unlock around this call
		//	due to the fact that IOCycleInitialize might not return for a while because it might
		//	have to wait for the hardware to start.
		if(wasLocked)
		{
			mIOGuard.Unlock();
		}
		
		//	tell the device that the IO cycle is initializing to start the timing services
		mDevice->StartIOCycleTimingServices();
		
		//	set the device state to know the engine is running
		mDevice->IOEngineStarted();
		
		//	notify clients that the engine is running
		mDevice->PropertiesChanged(1, &theIsRunningAddress);
		
		//	re-lock the guard
		wasLocked = mIOGuard.Lock();

		//	make sure the thread is still running before moving on
		if(!mStopWorkLoop)
		{
			//	set the time constraints for the IOThread
			SetTimeConstraints();
			
			//	initialize the clock
			mDevice->EstablishIOCycleAnchorTime(mAnchorTime);
			mFrameCounter = 0;
			
#if	Offset_For_Input
			if(mDevice->HasInputStreams())
			{
				//	the first sleep cycle as to be at least the input safety offset and a buffer's
				//	worth of time to be sure that the input data is all there
				mFrameCounter += mDevice->GetSafetyOffset(true);
			}
#endif
			
			//	enter the work loop
			mWorkLoopPhase = kRunningPhase;
			bool isInNeedOfResynch = false;
			mDevice->GetIOCycleTelemetry().IOCycleInitializeEnd(mIOCycleCounter, mAnchorTime);
			while(!mStopWorkLoop)
			{
				//	get the current time
				AudioTimeStamp theCurrentTime;
				mDevice->GetCurrentTime(theCurrentTime);
				
				//	calculate the next wake up time
				AudioTimeStamp theNextWakeUpTime = CAAudioTimeStamp::kZero;
				theNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
				if(CalculateNextWakeUpTime(theCurrentTime, theNextWakeUpTime, isInNeedOfResynch, wasLocked))
				{
					//	sleep until the  next wake up time
					mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime);
					mIOGuard.WaitUntil(CAHostTimeBase::ConvertToNanos(theNextWakeUpTime.mHostTime));
					
					//	increment the counter
					++mIOCycleCounter;
					
					//	do IO if the thread wasn't stopped
					if(!mStopWorkLoop)
					{
						//	get the current time
						mDevice->GetCurrentTime(theCurrentTime);
						
						#if Log_SchedulingLatency
							//	check to see if we have incurred a large scheduling latency
							if(theCurrentTime.mHostTime > (theNextWakeUpTime.mHostTime + mAllowedLatency))
							{
								//	log it
								mLatencyLog->Capture(theNextWakeUpTime.mHostTime - mAllowedLatency, theCurrentTime.mHostTime, true);
								
								//	print how late we are
								DebugMessageN1("HP_IOThread::WorkLoop: woke up late by %f milliseconds", ((Float64)CAHostTimeBase::ConvertToNanos(theCurrentTime.mHostTime - theNextWakeUpTime.mHostTime)) / (1000.0 * 1000.0));
							}
						#endif
						
						if(theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter))
						{
							//	increment the frame counter
							mFrameCounter += mDevice->GetIOBufferFrameSize();
						
							//	the new cycle is starting
							mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime);
							if(mDevice->UpdateIOCycleTimingServices())
							{
								//	something unexpected happenned with the time stamp, so resynch prior to doing IO
								AudioTimeStamp theNewAnchor = CAAudioTimeStamp::kZero;
								theNewAnchor.mSampleTime = 0;
								theNewAnchor.mHostTime = 0;
								theNewAnchor.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
								if(mDevice->EstablishIOCycleAnchorTime(theNewAnchor))
								{
									Resynch(&theNewAnchor, false);
								}
								else
								{
									Resynch(NULL, false);
								}
								
								//	re-get the current time too
								mDevice->GetCurrentTime(theCurrentTime);
							}
						
							//	do the IO
							isInNeedOfResynch = PerformIO(theCurrentTime);
						}
					}
				}
				else
				{
					//	calculating the next wake up time failed, so we just stop everything (which
					//	will get picked up when the commands are executed
					mDevice->ClearAllCommands();
					mDevice->Do_StopAllIOProcs();
				}
				
				//	execute any deferred commands
				mDevice->ExecuteAllCommands();
			}
		}
	
		mWorkLoopPhase = kTeardownPhase;
		mDevice->GetIOCycleTelemetry().IOCycleTeardownBegin(mIOCycleCounter);

		//	the work loop has finished, clear the time constraints
		ClearTimeConstraints();
		
		//	tell the device that the IO thread is torn down
		mDevice->StopIOCycleTimingServices();
	}
	catch(const CAException& inException)
	{
		DebugMessageN1("HP_IOThread::WorkLoop: Caught a CAException, code == %ld", (long int)inException.GetError());
	}
	catch(...)
	{
		DebugMessage("HP_IOThread::WorkLoop: Caught an unknown exception.");
	}
	
	//	set the device state to know the engine has stopped
	mDevice->IOEngineStopped();
		
	//	Notify clients that the IO thread is stopping. Note that we unlock around this call
	//	due to the fact that clients might want to call back into the HAL.
	if(wasLocked)
	{
		mIOGuard.Unlock();
	}

	//	Notify clients that the IO thread is stopping
	mDevice->PropertiesChanged(1, &theIsRunningAddress);
		
	//	re-lock the guard
	wasLocked = mIOGuard.Lock();

	mDevice->GetIOCycleTelemetry().IOCycleTeardownEnd(mIOCycleCounter);
	mWorkLoopPhase = kNotRunningPhase;
	mIOGuard.NotifyAll();
	mIOCycleCounter = 0;
	
	if(wasLocked)
	{
		mIOGuard.Unlock();
	}
}
Ejemplo n.º 20
0
bool	ZKMORHP_IOThreadSlave::CalculateNextWakeUpTime(const AudioTimeStamp& inCurrentTime, AudioTimeStamp& outNextWakeUpTime, bool inMustResynch, bool& inIOGuardWasLocked)
{
	bool theAnswer = true;
	
//	static const Float64 kOverloadThreshold = 0.050;
	static const Float64 kOverloadThreshold = 0.000;
	bool isDone = false;
	AudioTimeStamp theCurrentTime = inCurrentTime;
	
	int theNumberIterations = 0;
	while(!isDone)
	{
		++theNumberIterations;
		Float64 theIOBufferFrameSize = mDevice->GetIOBufferFrameSize();
		
		//	set up the outNextWakeUpTime
		outNextWakeUpTime = CAAudioTimeStamp::kZero;
		outNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
		
		//	set up the overload time
		AudioTimeStamp theOverloadTime = CAAudioTimeStamp::kZero;
		theOverloadTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid;
		
		//	calculate the sample time for the next wake up time
		AudioTimeStamp theSampleTime = mAnchorTime;
		theSampleTime.mFlags = kAudioTimeStampSampleTimeValid;
		theSampleTime.mSampleTime += mFrameCounter;
		theSampleTime.mSampleTime += theIOBufferFrameSize;
		
		//	translate that to a host time
		mDevice->TranslateTime(theSampleTime, outNextWakeUpTime);
		
		//	calculate the overload time
		Float64 theReservedAmount = std::max(0.0, mIOCycleUsage - kOverloadThreshold);
		theSampleTime = mAnchorTime;
		theSampleTime.mFlags = kAudioTimeStampSampleTimeValid;
		theSampleTime.mSampleTime += mFrameCounter;
		theSampleTime.mSampleTime += theReservedAmount * theIOBufferFrameSize;
		
		//	translate that to a host time
		mDevice->TranslateTime(theSampleTime, theOverloadTime);
		
		if(inMustResynch || (theCurrentTime.mHostTime >= theOverloadTime.mHostTime))
		{
			//	tell the device what happenned
			mDevice->GetIOCycleTelemetry().IOCycleWorkLoopOverloadBegin(mIOCycleCounter, theCurrentTime, theOverloadTime);
			
			//	the current time is beyond the overload time, have to resynchronize
			#if Log_Resynchs
				if(inMustResynch)
				{
					DebugMessageN1("ZKMORHP_IOThreadSlave::CalculateNextWakeUpTime: resynch was forced %d", theNumberIterations);
				}
				else
				{
					DebugMessageN1("ZKMORHP_IOThreadSlave::CalculateNextWakeUpTime: wake up time is in the past... resynching %d", theNumberIterations);
					DebugMessageN3("           Now: %qd Overload: %qd Difference: %qd", CAHostTimeBase::ConvertToNanos(theCurrentTime.mHostTime), CAHostTimeBase::ConvertToNanos(theOverloadTime.mHostTime), CAHostTimeBase::ConvertToNanos(theCurrentTime.mHostTime - theOverloadTime.mHostTime));
				}
			#endif
			
			//	notify clients that the overload has taken place
			if(inIOGuardWasLocked)
			{
				mIOGuard.Unlock();
			}
			CAPropertyAddress theOverloadAddress(kAudioDeviceProcessorOverload);
			mDevice->PropertiesChanged(1, &theOverloadAddress);
			inIOGuardWasLocked = mIOGuard.Lock();

			//	re-anchor at the current time
			theCurrentTime.mSampleTime = 0;
			theCurrentTime.mHostTime = 0;
			if(mDevice->EstablishIOCycleAnchorTime(theCurrentTime))
			{
				Resynch(&theCurrentTime, false);
			}
			else
			{
				theAnswer = false;
				isDone = true;
			}
			
			//	reset the forced resynch flag
			inMustResynch = false;
			mDevice->GetIOCycleTelemetry().IOCycleWorkLoopOverloadEnd(mIOCycleCounter, mAnchorTime);
		}
		else
		{
			//	still within the limits
			isDone = true;
		}
	}
	
	//  adjust the counter depending on what happenned
	if(theNumberIterations > 1)
	{
		//  we went through the calculation more than once, which means an overload happenned
		++mOverloadCounter;
	}
	else
	{
		//  only did the calculation once, so no overload occurred
		mOverloadCounter = 0;
	}
	
	return theAnswer;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus	OALBuffer::AddAudioData(char*	inAudioData, UInt32	inAudioDataSize, ALenum format, ALsizei freq, bool	inPreConvertToHalFormat)
{
#if LOG_VERBOSE
	DebugMessageN6("OALBuffer::AddAudioData() - OALBuffer:inAudioData:inAudioDataSize:format:freq:inPreConvertToHalFormat = %ld:%p:%ld:%d:%d:%d", (long int) mSelfToken, inAudioData, (long int) inAudioDataSize, format, freq, inPreConvertToHalFormat);
#endif
	// creates memory if needed
	// reallocs if needed
	// returns an error if buffer is in use

	CAGuard::Locker bufferLock(mBufferLock);
	
	try {
        if (!IsFormatSupported(format))
           throw ((OSStatus) AL_INVALID_VALUE);   // this is not a valid buffer token or is an invalid format
	
#if USE_SOURCE_LIST_MUTEX
	bool wasLocked = mSourceListGuard.Lock();
#endif
		// don't allow if the buffer is in a queue
		UInt32	attachedCount = mAttachedSourceList->Size();

#if USE_SOURCE_LIST_MUTEX
		if (wasLocked) mSourceListGuard.Unlock();
#endif

        if (attachedCount > 0)
        {
			DebugMessage("WAITING: AddAudioData ---> WaitOneRenderCycle");
			// Let a render cycle go by and try again

			WaitOneRenderCycle();

#if USE_SOURCE_LIST_MUTEX
			wasLocked = mSourceListGuard.Lock();
#endif
			attachedCount = mAttachedSourceList->Size();

#if USE_SOURCE_LIST_MUTEX
			if (wasLocked) mSourceListGuard.Unlock();
#endif
			
			if (attachedCount > 0){
				DebugMessageN2("OALBuffer::AddAudioData: buffer ATTACHMENT > 0 - mSelfToken:mAttachedSourceList->Size() = %ld:%ld", (long int) mSelfToken, (long int) mAttachedSourceList->Size());
				throw ((OSStatus) AL_INVALID_OPERATION);   
			}
        }

		if (mAppOwnsBufferMemory)
		{
			mData = NULL;	// we were using the apps memory before so just initialize mData incase we fail
			mAppOwnsBufferMemory = false;
		}
		
        mPreConvertedDataSize = (UInt32) inAudioDataSize;
        // do not pre-convert stereo sounds, let the AC do the deinterleaving	
        OSStatus    result = noErr;
        if (!inPreConvertToHalFormat || ((format == AL_FORMAT_STEREO16) || (format == AL_FORMAT_STEREO8)))
        {
            if (mData != NULL)
            {
                if (mDataSize != (UInt32) inAudioDataSize)
                {
                    mDataSize = (UInt32) inAudioDataSize;
                    void *newDataPtr = realloc(mData, mDataSize);
                    mData = (UInt8 *) newDataPtr;
                }		
            }
            else
            {
                mDataSize = (UInt32) inAudioDataSize;
                mData = (UInt8 *) malloc (mDataSize);
            }
            
            if (mData)
            {
                result = FillInASBD(mDataFormat, format, freq);
                    THROW_RESULT
                
                mPreConvertedDataFormat.SetFrom(mDataFormat); //  make sure they are the same so original format info can be returned to caller
                memcpy (mData, inAudioData, mDataSize);		
            }
        }
        else
        {
    #if LOG_EXTRAS		
        DebugMessage("alBufferData called: Converting Data Now");
    #endif

            result = ConvertDataForBuffer(inAudioData, inAudioDataSize, format, freq);	// convert the data to the mixer's format and copy to the buffer
                THROW_RESULT
        }
    }
    catch (OSStatus     result) {
		DebugMessageN1("OALBuffer::AddAudioData Failed - err = %ld\n", (long int) result);
        alSetError(result);
		throw result;
    }
    catch (...) {
		DebugMessage("OALBuffer::AddAudioData Failed");
        alSetError(AL_INVALID_OPERATION);
		throw -1;
	}
			
	return noErr;
}
Ejemplo n.º 22
0
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;
}