• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 OBOE_LATENCY_TUNER_
18 #define OBOE_LATENCY_TUNER_
19 
20 #include <atomic>
21 #include <cstdint>
22 #include "oboe/Definitions.h"
23 #include "oboe/AudioStream.h"
24 
25 namespace oboe {
26 
27 /**
28  * LatencyTuner can be used to dynamically tune the latency of an output stream.
29  * It adjusts the stream's bufferSize by monitoring the number of underruns.
30  *
31  * This only affects the latency associated with the first level of buffering that is closest
32  * to the application. It does not affect low latency in the HAL, or touch latency in the UI.
33  *
34  * Call tune() right before returning from your data callback function if using callbacks.
35  * Call tune() right before calling write() if using blocking writes.
36  *
37  * If you want to see the ongoing results of this tuning process then call
38  * stream->getBufferSize() periodically.
39  *
40  */
41 class LatencyTuner {
42 public:
43 
44     /**
45      * Construct a new LatencyTuner object which will act on the given audio stream
46      *
47      * @param stream the stream who's latency will be tuned
48      */
49     explicit LatencyTuner(AudioStream &stream);
50 
51     /**
52      * Construct a new LatencyTuner object which will act on the given audio stream.
53      *
54      * @param stream the stream who's latency will be tuned
55      * @param the maximum buffer size which the tune() operation will set the buffer size to
56      */
57     explicit LatencyTuner(AudioStream &stream, int32_t maximumBufferSize);
58 
59     /**
60      * Adjust the bufferSizeInFrames to optimize latency.
61      * It will start with a low latency and then raise it if an underrun occurs.
62      *
63      * Latency tuning is only supported for AAudio.
64      *
65      * @return OK or negative error, ErrorUnimplemented for OpenSL ES
66      */
67     Result tune();
68 
69     /**
70      * This may be called from another thread. Then tune() will call reset(),
71      * which will lower the latency to the minimum and then allow it to rise back up
72      * if there are glitches.
73      *
74      * This is typically called in response to a user decision to minimize latency. In other words,
75      * call this from a button handler.
76      */
77     void requestReset();
78 
79     /**
80      * @return true if the audio stream's buffer size is at the maximum value. If no maximum value
81      * was specified when constructing the LatencyTuner then the value of
82      * stream->getBufferCapacityInFrames is used
83      */
84     bool isAtMaximumBufferSize();
85 
86     /**
87      * Set the minimum bufferSize in frames that is used when the tuner is reset.
88      * You may wish to call requestReset() after calling this.
89      * @param bufferSize
90      */
setMinimumBufferSize(int32_t bufferSize)91     void setMinimumBufferSize(int32_t bufferSize) {
92         mMinimumBufferSize = bufferSize;
93     }
94 
getMinimumBufferSize()95     int32_t getMinimumBufferSize() const {
96         return mMinimumBufferSize;
97     }
98 
99     /**
100      * Set the amount the bufferSize will be incremented while tuning.
101      * By default, this will be one burst.
102      *
103      * Note that AAudio will quantize the buffer size to a multiple of the burstSize.
104      * So the final buffer sizes may not be a multiple of this increment.
105      *
106      * @param sizeIncrement
107      */
setBufferSizeIncrement(int32_t sizeIncrement)108     void setBufferSizeIncrement(int32_t sizeIncrement) {
109         mBufferSizeIncrement = sizeIncrement;
110     }
111 
getBufferSizeIncrement()112     int32_t getBufferSizeIncrement() const {
113         return mBufferSizeIncrement;
114     }
115 
116 private:
117 
118     /**
119      * Drop the latency down to the minimum and then let it rise back up.
120      * This is useful if a glitch caused the latency to increase and it hasn't gone back down.
121      *
122      * This should only be called in the same thread as tune().
123      */
124     void reset();
125 
126     enum class State {
127         Idle,
128         Active,
129         AtMax,
130         Unsupported
131     } ;
132 
133     // arbitrary number of calls to wait before bumping up the latency
134     static constexpr int32_t kIdleCount = 8;
135     static constexpr int32_t kDefaultNumBursts = 2;
136 
137     AudioStream           &mStream;
138     State                 mState = State::Idle;
139     int32_t               mMaxBufferSize = 0;
140     int32_t               mPreviousXRuns = 0;
141     int32_t               mIdleCountDown = 0;
142     int32_t               mMinimumBufferSize;
143     int32_t               mBufferSizeIncrement;
144     std::atomic<int32_t>  mLatencyTriggerRequests{0}; // TODO user atomic requester from AAudio
145     std::atomic<int32_t>  mLatencyTriggerResponses{0};
146 };
147 
148 } // namespace oboe
149 
150 #endif // OBOE_LATENCY_TUNER_
151