1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
18 #define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
19 
20 #include <stdint.h>
21 
22 #include <audio_utils/Histogram.h>
23 
24 #include "utility/AudioClock.h"
25 
26 namespace aaudio {
27 
28 /**
29  * Model an isochronous data stream using occasional timestamps as input.
30  * This can be used to predict the position of the stream at a given time.
31  *
32  * This class is not thread safe and should only be called from one thread.
33  */
34 class IsochronousClockModel {
35 
36 public:
37     IsochronousClockModel();
38     virtual ~IsochronousClockModel() = default;
39 
40     void start(int64_t nanoTime);
41     void stop(int64_t nanoTime);
42 
43     /**
44      * @return true if the model is starting up
45      */
46     bool isStarting() const;
47 
48     /**
49      * @return true if the model is running and producing valid results
50      */
51     bool isRunning() const;
52 
53     void processTimestamp(int64_t framePosition, int64_t nanoTime);
54 
55     /**
56      * @param sampleRate rate of the stream in frames per second
57      */
58     void setSampleRate(int32_t sampleRate);
59 
60     void setPositionAndTime(int64_t framePosition, int64_t nanoTime);
61 
getSampleRate()62     int32_t getSampleRate() const {
63         return mSampleRate;
64     }
65 
66     /**
67      * This must be set accurately in order to track the isochronous stream.
68      *
69      * @param framesPerBurst number of frames that stream advance at one time.
70      */
71     void setFramesPerBurst(int32_t framesPerBurst);
72 
getFramesPerBurst()73     int32_t getFramesPerBurst() const {
74         return mFramesPerBurst;
75     }
76 
77     /**
78      * Calculate an estimated time when the stream will be at that position.
79      *
80      * @param framePosition position of the stream in frames
81      * @return time in nanoseconds
82      */
83     int64_t convertPositionToTime(int64_t framePosition) const;
84 
85     /**
86      * Calculate the latest estimated time that the stream will be at that position.
87      * The more jittery the clock is then the later this will be.
88      *
89      * @param framePosition
90      * @return time in nanoseconds
91      */
92     int64_t convertPositionToLatestTime(int64_t framePosition) const;
93 
94     /**
95      * Calculate an estimated position where the stream will be at the specified time.
96      *
97      * @param nanoTime time of interest
98      * @return position in frames
99      */
100     int64_t convertTimeToPosition(int64_t nanoTime) const;
101 
102     /**
103      * Calculate the corresponding estimated position based on the specified time being
104      * the latest possible time.
105      *
106      * For the same nanoTime, this may return an earlier position than
107      * convertTimeToPosition().
108      *
109      * @param nanoTime
110      * @return position in frames
111      */
112     int64_t convertLatestTimeToPosition(int64_t nanoTime) const;
113 
114     /**
115      * @param framesDelta difference in frames
116      * @return duration in nanoseconds
117      */
118     int64_t convertDeltaPositionToTime(int64_t framesDelta) const;
119 
120     /**
121      * @param nanosDelta duration in nanoseconds
122      * @return frames that stream will advance in that time
123      */
124     int64_t convertDeltaTimeToPosition(int64_t nanosDelta) const;
125 
126     void dump() const;
127 
128     void dumpHistogram() const;
129 
130 private:
131 
132     void driftForward(int64_t latenessNanos,
133                       int64_t expectedNanosDelta,
134                       int64_t framePosition);
135     int32_t getLateTimeOffsetNanos() const;
136     void update();
137 
138     enum clock_model_state_t {
139         STATE_STOPPED,
140         STATE_STARTING,
141         STATE_SYNCING,
142         STATE_RUNNING
143     };
144 
145     // Maximum amount of time to drift forward when we get a late timestamp.
146     static constexpr int64_t   kMaxDriftNanos      = 10 * AAUDIO_NANOS_PER_MICROSECOND;
147     // Safety margin to add to the late edge of the timestamp window.
148     static constexpr int32_t   kExtraLatenessNanos = 100 * AAUDIO_NANOS_PER_MICROSECOND;
149     // Predicted lateness due to scheduling jitter in the HAL timestamp collection.
150     static constexpr int32_t   kLatenessMarginForSchedulingJitter
151             = 1000 * AAUDIO_NANOS_PER_MICROSECOND;
152     // Amount we multiply mLatenessForDriftNanos to get mLatenessForJumpNanos.
153     // This determines when we go from thinking the clock is drifting to
154     // when it has actually paused briefly.
155     static constexpr int32_t   kScalerForJumpLateness = 5;
156     // Amount to divide lateness past the expected burst window to generate
157     // the drift value for the window. This is meant to be a very slight nudge forward.
158     static constexpr int32_t   kShifterForDrift = 6; // divide by 2^N
159     static constexpr int32_t   kVeryLateCountsNeededToTriggerJump = 2;
160 
161     static constexpr int32_t   kHistogramBinWidthMicros = 50;
162     static constexpr int32_t   kHistogramBinCount       = 128;
163 
164     int64_t             mMarkerFramePosition{0}; // Estimated HW position.
165     int64_t             mMarkerNanoTime{0};      // Estimated HW time.
166     int64_t             mBurstPeriodNanos{0};    // Time between HW bursts.
167     // Includes mBurstPeriodNanos because we sample randomly over time.
168     int64_t             mMaxMeasuredLatenessNanos{0};
169     // Threshold for lateness that triggers a drift later in time.
170     int64_t             mLatenessForDriftNanos{0}; // Set in update()
171     // Based on the observed lateness when the DSP is paused for playing a touch sound.
172     int64_t             mLatenessForJumpNanos{0}; // Set in update()
173     int64_t             mLastJumpWarningTimeNanos{0}; // For throttling warnings.
174 
175     int32_t             mSampleRate{48000};
176     int32_t             mFramesPerBurst{48};     // number of frames transferred at one time.
177     int32_t             mConsecutiveVeryLateCount{0};  // To detect persistent DSP lateness.
178 
179     clock_model_state_t mState{STATE_STOPPED};   // State machine handles startup sequence.
180 
181     int32_t             mTimestampCount = 0;  // For logging.
182     int32_t             mDspStallCount = 0;  // For logging.
183 
184     // distribution of timestamps relative to earliest
185     std::unique_ptr<android::audio_utils::Histogram>   mHistogramMicros;
186 
187 };
188 
189 } /* namespace aaudio */
190 
191 #endif //ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
192