Oboe
A library for creating real-time audio apps on Android
|
#include <AudioStream.h>
Protected Member Functions | |
bool | wasErrorCallbackCalled () |
virtual Result | waitForStateTransition (StreamState startingState, StreamState endingState, int64_t timeoutNanoseconds) |
virtual DataCallbackResult | onDefaultCallback (void *, int) |
DataCallbackResult | fireDataCallback (void *audioData, int numFrames) |
bool | isDataCallbackEnabled () |
void | setDataCallbackEnabled (bool enabled) |
void | calculateDefaultDelayBeforeCloseMillis () |
void | sleepBeforeClose () |
virtual void | beginPerformanceHintInCallback () |
virtual void | endPerformanceHintInCallback (int32_t) |
virtual void | closePerformanceHint () |
void | setWeakThis (std::shared_ptr< oboe::AudioStream > &sharedStream) |
std::shared_ptr< oboe::AudioStream > | lockWeakThis () |
Protected Member Functions inherited from oboe::AudioStreamBase | |
virtual Result | isValidConfig () |
Protected Attributes | |
std::weak_ptr< AudioStream > | mWeakThis |
std::atomic< int64_t > | mFramesWritten {} |
std::atomic< int64_t > | mFramesRead {} |
std::mutex | mLock |
oboe::Result | mErrorCallbackResult = oboe::Result::OK |
int32_t | mFramesPerBurst = kUnspecified |
int32_t | mDelayBeforeCloseMillis = kMinDelayBeforeCloseMillis |
Protected Attributes inherited from oboe::AudioStreamBase | |
AudioStreamDataCallback * | mDataCallback = nullptr |
std::shared_ptr< AudioStreamDataCallback > | mSharedDataCallback |
AudioStreamErrorCallback * | mErrorCallback = nullptr |
std::shared_ptr< AudioStreamErrorCallback > | mSharedErrorCallback |
int32_t | mFramesPerCallback = kUnspecified |
int32_t | mChannelCount = kUnspecified |
int32_t | mSampleRate = kUnspecified |
int32_t | mDeviceId = kUnspecified |
int32_t | mBufferCapacityInFrames = kUnspecified |
int32_t | mBufferSizeInFrames = kUnspecified |
ChannelMask | mChannelMask = ChannelMask::Unspecified |
SharingMode | mSharingMode = SharingMode::Shared |
AudioFormat | mFormat = AudioFormat::Unspecified |
Direction | mDirection = Direction::Output |
PerformanceMode | mPerformanceMode = PerformanceMode::None |
Usage | mUsage = Usage::Media |
ContentType | mContentType = ContentType::Music |
InputPreset | mInputPreset = InputPreset::VoiceRecognition |
SessionId | mSessionId = SessionId::None |
AllowedCapturePolicy | mAllowedCapturePolicy = AllowedCapturePolicy::Unspecified |
PrivacySensitiveMode | mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified |
std::string | mPackageName |
std::string | mAttributionTag |
bool | mIsContentSpatialized = false |
SpatializationBehavior | mSpatializationBehavior = SpatializationBehavior::Unspecified |
int32_t | mHardwareChannelCount = kUnspecified |
int32_t | mHardwareSampleRate = kUnspecified |
AudioFormat | mHardwareFormat = AudioFormat::Unspecified |
bool | mChannelConversionAllowed = false |
bool | mFormatConversionAllowed = false |
SampleRateConversionQuality | mSampleRateConversionQuality = SampleRateConversionQuality::Medium |
Static Protected Attributes | |
static constexpr int | kMinDelayBeforeCloseMillis = 10 |
Friends | |
class | AudioStreamBuilder |
Base class for Oboe C++ audio stream.
|
explicit |
Construct an AudioStream
using the given AudioStreamBuilder
builder | containing all the stream's attributes |
This may be called internally at the beginning of a callback.
|
protected |
This should only be called as a stream is being opened. Otherwise we might override setDelayBeforeCloseMillis().
|
inlinevirtual |
Calculate the latency of a stream based on getTimestamp().
Output latency is the time it takes for a given frame to travel from the app to some type of digital-to-analog converter. If the DAC is external, for example in a USB interface or a TV connected by HDMI, then there may be additional latency that the Android device is unaware of.
Input latency is the time it takes to a given frame to travel from an analog-to-digital converter (ADC) to the app.
Note that the latency of an OUTPUT stream will increase abruptly when you write data to it and then decrease slowly over time as the data is consumed.
The latency of an INPUT stream will decrease abruptly when you read data from it and then increase slowly over time as more data arrives.
The latency of an OUTPUT stream is generally higher than the INPUT latency because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty.
Note that due to issues in Android before R, we recommend NOT calling this method from a data callback. See this tech note for more details. https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer
|
virtual |
Close the stream and deallocate any resources from the open() call.
This will be called when the stream is closed just in case performance hints were enabled.
This may be called internally at the end of a callback.
numFrames | passed to the callback |
|
protected |
Override this to provide your own behaviour for the audio callback
audioData | container array which audio frames will be written into or read from |
numFrames | number of frames which were read/written |
|
virtual |
Flush the stream. This will block until the stream has been flushed, an error occurs or timeoutNanoseconds
has been reached.
|
pure virtual |
Get the underlying audio API which the stream uses.
ResultWithValue< int32_t > oboe::AudioStream::getAvailableFrames | ( | ) |
|
inline |
Get the number of bytes in each audio frame. This is calculated using the channel count and the sample format. For example, a 2 channel floating point stream will have 2 * 4 = 8 bytes per frame.
int32_t oboe::AudioStream::getBytesPerSample | ( | ) | const |
Get the number of bytes per sample. This is calculated using the sample format. For example, a stream using 16-bit integer samples will have 2 bytes per sample.
|
inline |
Query the number of frames that are read or written by the endpoint at one time.
The number of audio frames read from the stream. This monotonic counter will never get reset.
The number of audio frames written into the stream. This monotonic counter will never get reset.
|
inlinevirtual |
|
pure virtual |
Query the current state, eg. StreamState::Pausing
|
virtual |
Get the estimated time that the frame at framePosition
entered or left the audio processing pipeline.
This can be used to coordinate events and interactions with the external environment, and to estimate the latency of an audio stream. An example of usage can be found in the hello-oboe sample (search for "calculateCurrentOutputLatencyMillis").
The time is based on the implementation's best effort, using whatever knowledge is available to the system, but cannot account for any delay unknown to the implementation.
Note that due to issues in Android before R, we recommend NOT calling this method from a data callback. See this tech note for more details. https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer
See
clockId | the type of clock to use e.g. CLOCK_MONOTONIC |
Get the estimated time that the frame at framePosition
entered or left the audio processing pipeline.
This can be used to coordinate events and interactions with the external environment, and to estimate the latency of an audio stream. An example of usage can be found in the hello-oboe sample (search for "calculateCurrentOutputLatencyMillis").
The time is based on the implementation's best effort, using whatever knowledge is available to the system, but cannot account for any delay unknown to the implementation.
Note that due to issues in Android before R, we recommend NOT calling this method from a data callback. See this tech note for more details. https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer
clockId | the type of clock to use e.g. CLOCK_MONOTONIC |
framePosition | the frame number to query |
timeNanoseconds | an output parameter which will contain the presentation timestamp |
Only for debugging. Do not use in production. If you need to call this method something is wrong. If you think you need it for production then please let us know so we can modify Oboe so that you don't need this.
|
inlinevirtual |
An XRun is an Underrun or an Overrun. During playing, an underrun will occur if the stream is not written in time and the system runs out of valid data. During recording, an overrun will occur if the stream is not read in time and there is no place to put the incoming data so it is discarded.
An underrun or overrun can cause an audible "pop" or "glitch".
|
inlineprotected |
|
inline |
This only tells you if the feature has been requested. It does not tell you if the PerformanceHint feature is implemented or active on the device.
|
inlineprotectedvirtual |
Override this to provide a default for when the application did not specify a callback.
audioData | |
numFrames |
|
inlinevirtual |
Open a stream based on the current settings.
Note that we do not recommend re-opening a stream that has been closed. TODO Should we prevent re-opening?
|
virtual |
Pause the stream. This will block until the stream has been paused, an error occurs or timeoutNanoseconds
has been reached.
|
inlinevirtual |
Read data into the supplied buffer from the stream. This method will block until the read is complete or it runs out of time.
If timeoutNanoseconds
is zero then this call will not wait.
buffer | The address of the first sample. |
numFrames | Number of frames to read. Only complete frames will be read. |
timeoutNanoseconds | Maximum number of nanoseconds to wait for completion. |
|
inlinevirtual |
Free the audio resources associated with a stream created by AAudioStreamBuilder_openStream().
AAudioStream_close() should be called at some point after calling this function.
After this call, the stream will be in AAUDIO_STREAM_STATE_CLOSING
This function is useful if you want to release the audio resources immediately, but still allow queries to the stream to occur from other threads. This often happens if you are monitoring stream progress from a UI thread.
NOTE: This function is only fully implemented for MMAP streams, which are low latency streams supported by some devices. On other "Legacy" streams some audio resources will still be in use and some callbacks may still be in process after this call.
Available in AAudio since API level 30. Returns Result::ErrorUnimplemented otherwise.
Use this to give the performance manager more information about your workload. You can call this at the beginning of the callback when you figure out what your workload will be.
Call this if (1) you have called setPerformanceHintEnabled(true), and (2) you have a varying workload, and (3) you hear glitches when your workload suddenly increases.
This might happen when you go from a single note to a big chord on a synthesizer.
The workload can be in your own units. If you are synthesizing music then the workload could be the number of active voices. If your app is a game then it could be the number of sound effects. The units are arbitrary. They just have to be proportional to the estimated computational load. For example, if some of your voices take 20% more computation than a basic voice then assign 6 units to the complex voice and 5 units to the basic voice.
The performance hint code can use this as an advance warning that the callback duration will probably increase. Rather than wait for the long duration and possibly under-run, we can boost the CPU immediately before we start doing the calculations.
appWorkload | workload in application units, such as number of voices |
|
pure virtual |
Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling flush(0)
.
|
pure virtual |
Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling pause(0)
.
|
pure virtual |
Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling start(0)
.
|
pure virtual |
Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling stop(0)
.
|
inlinevirtual |
This can be used to adjust the latency of the buffer by changing the threshold where blocking will occur. By combining this with getXRunCount(), the latency can be tuned at run-time for each device.
This cannot be set higher than getBufferCapacity().
This should only be used with Output streams. It will be ignored for Input streams because they are generally kept as empty as possible.
For OpenSL ES, this method only has an effect on output stream that do NOT use a callback. The blocking writes goes into a buffer in Oboe and the size of that buffer is controlled by this method.
requestedFrames | requested number of frames that can be filled without blocking |
This can be set false internally to prevent callbacks after DataCallbackResult::Stop has been returned.
Set the time to sleep before closing the internal stream.
Sometimes a callback can occur shortly after a stream has been stopped and even after a close! If the stream has been closed then the callback might access memory that has been freed, which could cause a crash. This seems to be more likely in Android P or earlier. But it can also occur in later versions. By sleeping, we give time for the callback threads to finish.
Note that this only has an effect when OboeGlobals::areWorkaroundsEnabled() is true.
delayBeforeCloseMillis | time to sleep before close. |
Enable or disable a device specific CPU performance hint. Runtime benchmarks such as the callback duration may be used to speed up the CPU and improve real-time performance.
Note that this feature is device specific and may not be implemented. Also the benefits may vary by device.
The flag will be checked in the Oboe data callback. If it transitions from false to true then the PerformanceHint feature will be started. This only needs to be called once for each stream.
You may want to enable this if you have a dynamically changing workload and you notice that you are getting under-runs and glitches when your workload increases. This might happen, for example, if you suddenly go from playing one note to ten notes on a synthesizer.
Try the "CPU Load" test in OboeTester if you would like to experiment with this interactively.
On some devices, this may be implemented using the "ADPF" library.
enabled | true if you would like a performance boost, default is false |
|
inlineprotected |
Try to avoid a race condition when closing.
|
virtual |
Start the stream. This will block until the stream has been started, an error occurs or timeoutNanoseconds
has been reached.
Stop the stream. This will block until the stream has been stopped, an error occurs or timeoutNanoseconds
has been reached.
Update mFramesRead. For internal use only.
Update mFramesWritten. For internal use only.
|
inline |
Returns true if the underlying audio API is AAudio.
ResultWithValue< int32_t > oboe::AudioStream::waitForAvailableFrames | ( | int32_t | numFrames, |
int64_t | timeoutNanoseconds | ||
) |
Wait until the stream has a minimum amount of data available in its buffer. This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to the DSP write position, which may cause glitches.
Starting with Oboe 1.7.1, the numFrames will be clipped internally against the BufferCapacity minus BurstSize. This is to prevent trying to wait for more frames than could possibly be available. In this case, the return value may be less than numFrames. Note that there may still be glitching if numFrames is too high.
numFrames | requested minimum frames available |
timeoutNanoseconds |
|
pure virtual |
Wait until the stream's current state no longer matches the input state. The input state is passed to avoid race conditions caused by the state changing between calls.
Note that generally applications do not need to call this. It is considered an advanced technique and is mostly used for testing.
int64_t timeoutNanos = 500 * kNanosPerMillisecond; // arbitrary 1/2 second
StreamState currentState = stream->getState();
StreamState nextState = StreamState::Unknown;
while (result == Result::OK && currentState != StreamState::Paused) {
result = stream->waitForStateChange(
currentState, &nextState, timeoutNanos);
currentState = nextState;
}
If the state does not change within the timeout period then it will return ErrorTimeout. This is true even if timeoutNanoseconds is zero.
inputState | The state we want to change away from. |
nextState | Pointer to a variable that will be set to the new state. |
timeoutNanoseconds | The maximum time to wait in nanoseconds. |
|
protectedvirtual |
Wait for a transition from one state to another.
|
inlineprotected |
This is used to detect more than one error callback from a stream. These were bugs in some versions of Android that caused multiple error callbacks. Internal bug b/63087953
Calling this sets an atomic<bool> true and returns the previous value.
|
inlinevirtual |
Write data from the supplied buffer into the stream. This method will block until the write is complete or it runs out of time.
If timeoutNanoseconds
is zero then this call will not wait.
buffer | The address of the first sample. |
numFrames | Number of frames to write. Only complete frames will be written. |
timeoutNanoseconds | Maximum number of nanoseconds to wait for completion. |
|
protected |
Number of frames which will be copied to/from the audio device in a single read/write operation
|
protected |
Number of frames which have been read from the stream.
This is signed integer to match the counters in AAudio. At audio rates, the counter will overflow in about six million years.
|
protected |
Number of frames which have been written into the stream
This is signed integer to match the counters in AAudio. At audio rates, the counter will overflow in about six million years.