void AUTimestampGenerator::AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj) { mState.mRateScalarAdj = rateScalarAdj; mState.mLastOutputTime = mState.mCurrentOutputTime; mState.mInputSampleTimeForOutputPull = mState.mNextInputSampleTime; mState.mCurrentOutputTime = inTimeStamp; if (mState.mBypassed) return; if (mState.mHostTimeDiscontinuityCorrection && !(mState.mCurrentOutputTime.mFlags & kAudioTimeStampHostTimeValid) && (mState.mLastOutputTime.mFlags & kAudioTimeStampHostTimeValid)) { // no host time here but we had one last time, interpolate one double rateScalar = (mState.mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) ? mState.mCurrentOutputTime.mRateScalar : 1.0; Float64 deltaSamples = mState.mCurrentOutputTime.mSampleTime - mState.mLastOutputTime.mSampleTime; mState.mCurrentOutputTime.mHostTime = mState.mLastOutputTime.mHostTime + UInt64(CAHostTimeBase::GetFrequency() * deltaSamples * rateScalar / outputSampleRate); mState.mCurrentOutputTime.mFlags |= kAudioTimeStampHostTimeValid; #if DEBUG if (mVerbosity > 1) printf("synthesized host time: %.3f (%.3f + %.f smp @ %.f Hz, rs %.3f\n", DebugHostTime(mState.mCurrentOutputTime), DebugHostTime(mState.mLastOutputTime), deltaSamples, outputSampleRate, rateScalar); #endif } // copy rate scalar if (rateScalarAdj != 1.0) { if (mState.mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) mState.mCurrentOutputTime.mRateScalar *= rateScalarAdj; else { mState.mCurrentOutputTime.mRateScalar = rateScalarAdj; mState.mCurrentOutputTime.mFlags |= kAudioTimeStampRateScalarValid; } } if (mFirstTime) { mFirstTime = false; mState.mDiscontinuous = false; mState.mDiscontinuityDeltaSamples = 0.; if (!mState.mStartInputAtZero) { mState.mNextInputSampleTime = mState.mCurrentOutputTime.mSampleTime; mState.mInputSampleTimeForOutputPull = mState.mNextInputSampleTime; } } else { mState.mDiscontinuous = fnotequal(mState.mCurrentOutputTime.mSampleTime, mState.mNextOutputSampleTime); mState.mDiscontinuityDeltaSamples = mState.mCurrentOutputTime.mSampleTime - mState.mNextOutputSampleTime; // time should never go backwards... if (mState.mDiscontinuityDeltaSamples < 0.) mState.mDiscontinuityDeltaSamples = 0.; #if DEBUG if (mVerbosity > 1) if (mState.mDiscontinuous) printf("%-20.20s: *** DISCONTINUOUS, got " TSGFMT ", expected " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentOutputTime.mSampleTime, (SInt64)mState.mNextOutputSampleTime); #endif } mState.mNextOutputSampleTime = mState.mCurrentOutputTime.mSampleTime + expectedDeltaFrames; }
const AudioTimeStamp & AUTimestampGenerator::GenerateInputTime(Float64 framesToAdvance, double inputSampleRate) { if (mBypassed) return mCurrentOutputTime; double inputSampleTime; mCurrentInputTime.mFlags = kAudioTimeStampSampleTimeValid; double rateScalar = 1.0; // propagate rate scalar if (mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) { mCurrentInputTime.mFlags |= kAudioTimeStampRateScalarValid; mCurrentInputTime.mRateScalar = rateScalar = mCurrentOutputTime.mRateScalar; } // propagate host time and sample time if (mCurrentOutputTime.mFlags & kAudioTimeStampHostTimeValid) { mCurrentInputTime.mFlags |= kAudioTimeStampHostTimeValid; mCurrentInputTime.mHostTime = mCurrentOutputTime.mHostTime; if (mHostTimeDiscontinuityCorrection && mDiscontinuous && (mLastOutputTime.mFlags & kAudioTimeStampHostTimeValid)) { // we had a discontinuous output time, need to resync by interpolating // a sample time that is appropriate to the host time UInt64 deltaHostTime = mCurrentOutputTime.mHostTime - mLastOutputTime.mHostTime; double deltaSeconds = double(deltaHostTime) * CAHostTimeBase::GetInverseFrequency(); // samples/second * seconds = samples double deltaSamples = floor(inputSampleRate / rateScalar * deltaSeconds + 0.5); double lastInputSampleTime = mCurrentInputTime.mSampleTime; inputSampleTime = lastInputSampleTime + deltaSamples; #if DEBUG if (mVerbosity > 1) printf("%-20.20s: adjusted input time: "TSGFMT" -> "TSGFMT" (SR=%.3f, rs=%.3f)\n", mDebugName, (SInt64)lastInputSampleTime, (SInt64)inputSampleTime, inputSampleRate, rateScalar); #endif mDiscontinuous = false; } else { inputSampleTime = mNextInputSampleTime; } } else { // we don't know the host time, so we can't do much inputSampleTime = mNextInputSampleTime; } if (!mHostTimeDiscontinuityCorrection && fnonzero(mDiscontinuityDeltaSamples)) { // we had a discontinuous output time, need to resync by propagating the // detected discontinuity, taking the rate scalar adjustment into account inputSampleTime += floor(mDiscontinuityDeltaSamples / mRateScalarAdj + 0.5); #if DEBUG if (mVerbosity > 1) printf("%-20.20s: adjusted input time: %.0f -> %.0f (SR=%.3f, rs=%.3f, delta=%.0f)\n", mDebugName, mNextInputSampleTime, inputSampleTime, inputSampleRate, mRateScalarAdj, mDiscontinuityDeltaSamples); #endif mDiscontinuityDeltaSamples = 0.; } // propagate word clock if (mCurrentOutputTime.mFlags & kAudioTimeStampWordClockTimeValid) { mCurrentInputTime.mFlags |= kAudioTimeStampWordClockTimeValid; mCurrentInputTime.mWordClockTime = mCurrentOutputTime.mWordClockTime; } // propagate SMPTE time if (mCurrentOutputTime.mFlags & kAudioTimeStampSMPTETimeValid) { mCurrentInputTime.mFlags |= kAudioTimeStampSMPTETimeValid; mCurrentInputTime.mSMPTETime = mCurrentOutputTime.mSMPTETime; } // store the input sample time and expected next input time mCurrentInputTime.mSampleTime = inputSampleTime; mNextInputSampleTime = inputSampleTime + framesToAdvance; #if DEBUG if (mVerbosity > 0) { printf("%-20.20s: out = "TSGFMT" (%10.3fs) in = "TSGFMT" (%10.3fs) delta = "TSGFMT" advance = "TSGFMT"\n", mDebugName, (SInt64)mCurrentOutputTime.mSampleTime, DebugHostTime(mCurrentOutputTime), (SInt64)inputSampleTime, DebugHostTime(mCurrentInputTime), (SInt64)(mCurrentOutputTime.mSampleTime - inputSampleTime), (SInt64)framesToAdvance); } #endif return mCurrentInputTime; }