// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Called by OALSource's BufferQueue::RemoveQueueEntryByIndex() class
bool	OALBuffer::ReleaseBuffer(OALSource*	inSource)
{
#if LOG_VERBOSE
	DebugMessageN2("OALBuffer::ReleaseBuffer() - OALBuffer:inSource = %ld:%ld", (long int) mSelfToken, (long int) inSource->GetToken());
#endif
	bool returnValue = false;
#if LOG_EXTRAS		
	DebugMessageN2("OALBuffer::ReleaseBuffer - BufferToken:SourceToken = %ld:%ld", mSelfToken, inSource->GetToken());
#endif

#if USE_SOURCE_LIST_MUTEX
	bool wasLocked = mSourceListGuard.Lock();
#endif

	// see if this source is in list already
	if (mAttachedSourceList->SourceExists(inSource) == true)
	{
		UInt32		attachmentCount = mAttachedSourceList->DecreaseAttachmentCount(inSource);
		if (attachmentCount == 0)
		{
			//DebugMessageN2("OALBuffer::ReleaseBuffer - BufferToken:SourceToken = %ld:%ld", (long int) mSelfToken, (long int) inSource->GetToken());
			mAttachedSourceList->Remove(inSource);
			returnValue = true;
		}
	}
	
#if USE_SOURCE_LIST_MUTEX
	if (wasLocked) mSourceListGuard.Unlock();
#endif

	return returnValue;
}
Ejemplo n.º 2
0
bool	CAGuard::WaitUntil(UInt64 inNanos)
{
	bool	theAnswer = false;
	UInt64	theCurrentNanos = CAHostTimeBase::GetCurrentTimeInNanos();
	
#if	Log_TimedWaits
	DebugMessageN2("CAGuard::WaitUntil: now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos);
#endif
	
	if(inNanos > theCurrentNanos)
	{
#if Log_Errors
		if((inNanos - theCurrentNanos) > 1000000000ULL)
		{
			DebugMessage("CAGuard::WaitUntil: about to wait for more than a second");
		}
#endif
		theAnswer = WaitFor(inNanos - theCurrentNanos);
	}
	else
	{
#if	Log_Errors
		DebugMessageN2("CAGuard::WaitUntil: Time has expired before waiting, now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos);
#endif
		theAnswer = true;
	}

	return theAnswer;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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;
}
OALCaptureDevice::OALCaptureDevice (const char* 	 inDeviceName, uintptr_t   inSelfToken, UInt32 inSampleRate, UInt32 inFormat, UInt32 inBufferSize)
	:
#if LOG_CAPTUREDEVICE_VERBOSE
        mSelfToken (inSelfToken),
#endif
		mCurrentError(ALC_NO_ERROR),
		mCaptureOn(false),
		mStoreSampleTime(0),
		mFetchSampleTime(0),
		mInputUnit(0),
		mRingBuffer(NULL),
		mBufferData(NULL),
		mSampleRateRatio(1.0),
		mRequestedRingFrames(inBufferSize),
		mAudioInputPtrs(NULL),
		mInUseFlag(0)
{
    char        *useThisDevice = (char *) inDeviceName;
	
	try {
		// translate the sample rate and data format parameters into an ASBD - this method throws
		FillInASBD(mRequestedFormat, inFormat, inSampleRate);

		// inBufferSize must be at least as big as one packet of the requested output formnat
		if (inBufferSize < mRequestedFormat.mBytesPerPacket)
           throw ((OSStatus) AL_INVALID_VALUE);
					
		// until the ALC_ENUMERATION_EXT extension is supported only use the default input device
        useThisDevice = NULL;
		
		InitializeAU(useThisDevice);

		if(mRequestedFormat.mSampleRate != mNativeFormat.mSampleRate)
		{
#if LOG_CAPTURE
	DebugMessageN2("OALCaptureDevice::OALCaptureDevice - Hardware Sample Rate: %5.1f Requested Sample Rate: %5.1f", mNativeFormat.mSampleRate, mRequestedFormat.mSampleRate);
#endif
			mSampleRateRatio = mNativeFormat.mSampleRate / mRequestedFormat.mSampleRate;
			mBufferData = (UInt8*)malloc(mRequestedFormat.mBytesPerFrame*mRequestedRingFrames*mSampleRateRatio);
			OSStatus result = AudioConverterNew(&mOutputFormat, &mRequestedFormat, &mAudioConverter);
				THROW_RESULT
		}
		
		mAudioInputPtrs = CABufferList::New("WriteBufferList", mRequestedFormat);
		
		mRingBuffer =  new OALRingBuffer();
		mRingBuffer->Allocate(mRequestedFormat.mBytesPerFrame, mRequestedRingFrames*mSampleRateRatio);
				
	}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Methods called from OALSource objects
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UInt32 	OALBuffer::GetFramesToBytes(UInt32	inOffsetInFrames) 
{
#if LOG_VERBOSE
	DebugMessageN2("OALBuffer::GetFramesToBytes() - OALBuffer:inOffsetInFrames = %ld:%ld", (long int) mSelfToken, (long int) inOffsetInFrames);
#endif
	UInt32		returnValue = 0;

	if (GetFramesPerPacket() == 1)
	{
		// pcm - it's easy
		returnValue = inOffsetInFrames * GetBytesPerPacket();			
	}
	else
	{
		// discover which packet conatins the frame we want to offset to
		// CURRENTLY UNNECESSARY BECAUSE WE ARE ONLY STORING PCM DATA
	}
	
	return returnValue;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.º 7
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;
}
Ejemplo n.º 8
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;
}