OSStatus CAPlayThrough::InputProc(void *inRefCon,
									AudioUnitRenderActionFlags *ioActionFlags,
									const AudioTimeStamp *inTimeStamp,
									UInt32 inBusNumber,
									UInt32 inNumberFrames,
									AudioBufferList * ioData)
{
    OSStatus err = noErr;

	CAPlayThrough *This = (CAPlayThrough *)inRefCon;
  This->mutex.lock();
	if (This->mFirstInputTime < 0.)
		This->mFirstInputTime = inTimeStamp->mSampleTime;
		
	//Get the new audio data
	err = AudioUnitRender(This->mInputUnit,
						 ioActionFlags,
						 inTimeStamp, 
						 inBusNumber,     
						 inNumberFrames, //# of frames requested
						 This->mInputBuffer);// Audio Buffer List to hold data
	checkErr(err);
		
	if(!err) {
    AEFloatConverterToFloat(This->converter,
                            This->mInputBuffer,
                            This->floatBuffers,
                            inNumberFrames);
    This->postNotification(This->floatBuffers, inNumberFrames);

		err = This->mBuffer->Store(This->mInputBuffer, Float64(inNumberFrames), SInt64(inTimeStamp->mSampleTime));
	}

  This->mutex.unlock();

	return err;
}
Example #2
0
OSStatus CAPlayThrough::OutputProc(void *inRefCon,
									 AudioUnitRenderActionFlags *ioActionFlags,
									 const AudioTimeStamp *TimeStamp,
									 UInt32 inBusNumber,
									 UInt32 inNumberFrames,
									 AudioBufferList * ioData)
{
    OSStatus err = noErr;
	CAPlayThrough *This = (CAPlayThrough *)inRefCon;
	Float64 rate = 0.0;
	AudioTimeStamp inTS, outTS;
		
	if (This->mFirstInputTime < 0.) {
		// input hasn't run yet -> silence
		MakeBufferSilent (ioData);
		return noErr;
	}
	
	//use the varispeed playback rate to offset small discrepancies in sample rate
	//first find the rate scalars of the input and output devices
	err = AudioDeviceGetCurrentTime(This->mInputDevice.mID, &inTS);
	// this callback may still be called a few times after the device has been stopped
	if (err)
	{
		MakeBufferSilent (ioData);
		return noErr;
	}
		
	err = AudioDeviceGetCurrentTime(This->mOutputDevice.mID, &outTS);
	checkErr(err);
	
	rate = inTS.mRateScalar / outTS.mRateScalar;
	err = AudioUnitSetParameter(This->mVarispeedUnit,kVarispeedParam_PlaybackRate,kAudioUnitScope_Global,0, rate,0);
	checkErr(err);
	
	//get Delta between the devices and add it to the offset
	if (This->mFirstOutputTime < 0.) {
		This->mFirstOutputTime = TimeStamp->mSampleTime;
		Float64 delta = (This->mFirstInputTime - This->mFirstOutputTime);
		This->ComputeThruOffset();   
		//changed: 3865519 11/10/04
		if (delta < 0.0)
			This->mInToOutSampleOffset -= delta;
		else
			This->mInToOutSampleOffset = -delta + This->mInToOutSampleOffset;
					
		MakeBufferSilent (ioData);
		return noErr;
	}

	//copy the data from the buffers	
	err = This->mBuffer->Fetch(ioData, inNumberFrames, SInt64(TimeStamp->mSampleTime - This->mInToOutSampleOffset));
	//old line of code different once ring buffer is replaced
	//err = This->mBuffer->Fetch(ioData, inNumberFrames, SInt64(TimeStamp->mSampleTime - This->mInToOutSampleOffset), false);	
	if(err != kCARingBufferError_OK)
	{
		MakeBufferSilent (ioData);
		SInt64 bufferStartTime, bufferEndTime;
		This->mBuffer->GetTimeBounds(bufferStartTime, bufferEndTime);
		This->mInToOutSampleOffset = TimeStamp->mSampleTime - bufferStartTime;
	}

	return noErr;
}
OSStatus CAPlayThrough::OutputProc(void *inRefCon,
									 AudioUnitRenderActionFlags *ioActionFlags,
									 const AudioTimeStamp *TimeStamp,
									 UInt32 inBusNumber,
									 UInt32 inNumberFrames,
									 AudioBufferList * ioData)
{
    OSStatus err = noErr;
	CAPlayThrough *This = (CAPlayThrough *)inRefCon;
	Float64 rate = 0.0;
	AudioTimeStamp inTS, outTS;
		
	if (This->mFirstInputTime < 0.) {
		// input hasn't run yet -> silence
		MakeBufferSilent (ioData);
		return noErr;
	}
	
	//use the varispeed playback rate to offset small discrepancies in sample rate
	//first find the rate scalars of the input and output devices
	err = AudioDeviceGetCurrentTime(This->mInputDevice.mID, &inTS);
	// this callback may still be called a few times after the device has been stopped
	if (err)
	{
		MakeBufferSilent (ioData);
		return noErr;
	}
		
	err = AudioDeviceGetCurrentTime(This->mOutputDevice.mID, &outTS);
	checkErr(err);
	
	rate = inTS.mRateScalar / outTS.mRateScalar;
	err = AudioUnitSetParameter(This->mVarispeedUnit,kVarispeedParam_PlaybackRate,kAudioUnitScope_Global,0, rate,0);
	checkErr(err);
	
	//get Delta between the devices and add it to the offset
	if (This->mFirstOutputTime < 0.) {
		This->mFirstOutputTime = TimeStamp->mSampleTime;
		Float64 delta = (This->mFirstInputTime - This->mFirstOutputTime);
		This->ComputeThruOffset();   
		//changed: 3865519 11/10/04
		if (delta < 0.0)
			This->mInToOutSampleOffset -= delta;
		else
			This->mInToOutSampleOffset = -delta + This->mInToOutSampleOffset;
		
        CAPT_DEBUG( "Set initial IOOffset to %f.\n", This->mInToOutSampleOffset );
                                			
		MakeBufferSilent (ioData);
		return noErr;
	}

	//copy the data from the buffers	
	err = This->mBuffer->Fetch(ioData, inNumberFrames, SInt64(TimeStamp->mSampleTime - This->mInToOutSampleOffset));	
	if( err != kCARingBufferError_OK ) {
        SInt64 bufferStartTime, bufferEndTime;
		This->mBuffer->GetTimeBounds( bufferStartTime, bufferEndTime );
        CAPT_DEBUG( "Oops. Adjusting IOOffset from %f, ", This->mInToOutSampleOffset );
        if ( err < kCARingBufferError_OK ) {
            CAPT_DEBUG( "ahead " );
            if ( err == kCARingBufferError_WayBehind ) {
                MakeBufferSilent( ioData );
            }
            This->mInToOutSampleOffset += std::max( ( TimeStamp->mSampleTime - This->mInToOutSampleOffset ) - bufferStartTime, kAdjustmentOffsetSamples );
        }
        else if ( err > kCARingBufferError_OK ) {
            CAPT_DEBUG( "behind " );
            if ( err == kCARingBufferError_WayAhead ) {
                MakeBufferSilent( ioData );
            }
            // Adjust by the amount that we read past in the buffer
            This->mInToOutSampleOffset += std::max( ( ( TimeStamp->mSampleTime - This->mInToOutSampleOffset ) + inNumberFrames ) - bufferEndTime, kAdjustmentOffsetSamples );
        }
        CAPT_DEBUG( "to %f.\n", This->mInToOutSampleOffset );
		MakeBufferSilent ( ioData );
	}

	return noErr;
}