Take a look at the following example: https://github.com/googlesamples/android-audio-high-performance/tree/master/SimpleSynth
It includes a “load stabilizer” class: https://github.com/googlesamples/android-audio-high-performance/blob/master/SimpleSynth/app/src/main/cpp/load_stabilizer.cc
It works as follows:
When you construct the load stabilizer you must specify:
#1 the callback period (i.e. the optimal delta between successive callbacks)
#2 the object which will do your actual audio rendering
You then call the load stabilizer
render method inside your audio callback. The stabilizer will render your audio data, then attempt to keep spinning the CPU for a certain percentage of the callback period (specified by
PERCENTAGE_OF_CALLBACK_TO_USE) including compensation if the callback started late. Personally I’ve found around 80% works best although YMMV.
Note that this is not really the “recommended” approach as it works against the CPU governor, however, the CPU governor is not designed to support real-time use cases so in some cases this is the only way you can achieve good latency with underrun protection.
Also worth mentioning that AAudio (on API 26+) has a better timing model and therefore has significantly less jitter on the audio callback than OpenSL ES.
does OBOE include some code to simplify this?
Not yet, but if you feel that this would be useful please file an issue: https://github.com/google/oboe/issues