1 /*
2      File: AUTimestampGenerator.h
3  Abstract: Part of CoreAudio Utility Classes
4   Version: 1.1
5 
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12 
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28 
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43 
44  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45 
46 */
47 #ifndef __AUTimestampGenerator_h__
48 #define __AUTimestampGenerator_h__
49 
50 #include <math.h>
51 #include "CAHostTimeBase.h"
52 #include <stdio.h>
53 
54 #define TSGFMT "0x%10qx"
55 //#define TSGFMT "%10qd"
56 
57 // This class generates a continuously increasing series of timestamps based
58 // on a series of potentially discontinuous timestamps (as can be delivered from
59 // CoreAudio in the event of an overload or major engine change).
60 // N.B.: "output" = downstream (source) timestamp
61 //		 "input"  = upstream (derived) timestamp
62 class AUTimestampGenerator {
63 public:
64 	AUTimestampGenerator(bool hostTimeDiscontinuityCorrection = false)
65 	{
66 		mState.mStartInputAtZero = true;
67 		mState.mBypassed = false;
68 		mState.mHostTimeDiscontinuityCorrection = hostTimeDiscontinuityCorrection;
69 #if DEBUG
70 		mVerbosity = 0;
71 		snprintf(mDebugName, sizeof(mDebugName), "tsg @ %p", this);
72 #endif
73 		// CAHostTimeBase should be used instead of the calls in <CoreAudio/HostTime.h>
74 		// we make this call here to ensure that this is initialized, otherwise the first time
75 		// you do actually call CAHostTimeBase to do work, can be on the render thread, and lead to unwanted VM faults
76 		CAHostTimeBase::GetFrequency();
77 		Reset();
78 	}
79 
SetStartInputAtZero(bool b)80 	void	SetStartInputAtZero(bool b) { mState.mStartInputAtZero = b; }
GetStartInputAtZero()81 	bool	GetStartInputAtZero() const { return mState.mStartInputAtZero; }
82 
83 	// bypassing is intended for a narrow special case. the upstream sample time will always be the same as the downstream time.
SetBypassed(bool b)84 	void	SetBypassed(bool b) { mState.mBypassed = b; }
GetBypassed()85 	bool	GetBypassed() const { return mState.mBypassed; }
86 
87 	// Call this to reset the timeline.
Reset()88 	void	Reset()
89 	{
90 		mState.mCurrentInputTime.mSampleTime = 0.;
91 		mState.mNextInputSampleTime = 0.;
92 		mState.mCurrentOutputTime.mSampleTime = 0.;
93 		mState.mNextOutputSampleTime = 0.;
94 		mState.mLastOutputTime.mFlags = 0;
95 		mState.mRateScalarAdj = 1.;
96 
97 		mFirstTime = true;
98 #if DEBUG
99 		if (mVerbosity)
100 			printf("%-20.20s: Reset\n", mDebugName);
101 #endif
102 	}
103 
104 	// Call this once per render cycle with the downstream timestamp.
105 	// expectedDeltaFrames is the expected difference between the current and NEXT
106 	//	downstream timestamps.
107 	// sampleRate is the OUTPUT sample rate.
108 	void	AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj=1.0);
109 
110 	// Call this once per render cycle to obtain the upstream timestamp.
111 	// framesToAdvance is the number of frames the input timeline is to be
112 	//	advanced during this render cycle.
113 	// sampleRate is the INPUT sample rate.
114 	const AudioTimeStamp &	GenerateInputTime(Float64 framesToAdvance, double inputSampleRate, bool advanceHostTime = false);
115 
116 	// this can be called to override the setting of the next input sample time in GenerateInputTime
Advance(Float64 framesToAdvance)117 	void					Advance(Float64 framesToAdvance)
118 	{
119 #if DEBUG
120 		if (mVerbosity > 1)
121 			printf("%-20.20s:	ADVANCE         in = " TSGFMT "                    advance = " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentInputTime.mSampleTime, (SInt64)framesToAdvance);
122 #endif
123 		mState.mNextInputSampleTime = mState.mCurrentInputTime.mSampleTime + framesToAdvance;
124 	}
125 
126 	struct State {
127 		AudioTimeStamp		mCurrentInputTime;
128 		Float64				mNextInputSampleTime;
129 		Float64				mNextOutputSampleTime;
130 		Float64				mInputSampleTimeForOutputPull;
131 
132 		AudioTimeStamp		mLastOutputTime;
133 		AudioTimeStamp		mCurrentOutputTime;
134 
135 		bool				mStartInputAtZero;  // if true, input timeline starts at 0, else it starts
136 												// synced with the output timeline
137 		bool				mDiscontinuous;
138 		bool				mBypassed;
139 		Float64				mDiscontinuityDeltaSamples;
140 
141 		double				mRateScalarAdj;
142 
143 		bool				mHostTimeDiscontinuityCorrection; // If true, propagate timestamp discontinuities using host time.
144 	};
145 
GetState(State & outState)146 	void GetState(State& outState) const { outState = mState; }
SetState(State const & inState)147 	void SetState(State const& inState) { mState = inState; mFirstTime = false; }
148 
149 private:
150 
151 	struct State		mState;
152 
153 	bool				mFirstTime;
154 
155 #if DEBUG
156 public:
157 	int					mVerbosity;
158 	char				mDebugName[64];
159 #endif
160 };
161 
162 
163 #endif // __AUTimestampGenerator_h__
164