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