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     int32_t getLateTimeOffsetNanos() const;
133     void update();
134 
135     enum clock_model_state_t {
136         STATE_STOPPED,
137         STATE_STARTING,
138         STATE_SYNCING,
139         STATE_RUNNING
140     };
141 
142     // Amount of time to drift forward when we get a late timestamp.
143     static constexpr int32_t   kDriftNanos         =   1 * 1000;
144     // Safety margin to add to the late edge of the timestamp window.
145     static constexpr int32_t   kExtraLatenessNanos = 100 * 1000;
146     // Initial small threshold for causing a drift later in time.
147     static constexpr int32_t   kInitialLatenessForDriftNanos = 10 * 1000;
148 
149     static constexpr int32_t   kHistogramBinWidthMicros = 50;
150     static constexpr int32_t   kHistogramBinCount = 128;
151 
152     int64_t             mMarkerFramePosition; // Estimated HW position.
153     int64_t             mMarkerNanoTime;      // Estimated HW time.
154     int32_t             mSampleRate;
155     int32_t             mFramesPerBurst;      // number of frames transferred at one time.
156     int32_t             mBurstPeriodNanos;    // Time between HW bursts.
157     // Includes mBurstPeriodNanos because we sample randomly over time.
158     int32_t             mMaxMeasuredLatenessNanos;
159     // Threshold for lateness that triggers a drift later in time.
160     int32_t             mLatenessForDriftNanos;
161     clock_model_state_t mState;               // State machine handles startup sequence.
162 
163     int32_t             mTimestampCount = 0;  // For logging.
164 
165     // distribution of timestamps relative to earliest
166     std::unique_ptr<android::audio_utils::Histogram>   mHistogramMicros;
167 
168 };
169 
170 } /* namespace aaudio */
171 
172 #endif //ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
173