You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
3.2 KiB
72 lines
3.2 KiB
7 months ago
|
[Tech Notes Home](README.md)
|
||
|
|
||
|
# Assert in releaseBuffer()
|
||
|
|
||
|
There is a bug that can sometimes cause an assert in ClientProxy or AudioTrackShared::releaseBuffer() when headsets are connected or disconnected.
|
||
|
The bug was originally reported at: https://github.com/google/oboe/issues/535
|
||
|
|
||
|
You will see signatures like this in the logcat:
|
||
|
|
||
|
F AudioTrackShared: releaseBuffer: mUnreleased out of range, !(stepCount:96 <= mUnreleased:0 <= mFrameCount:480), BufferSizeInFrames:480
|
||
|
|
||
|
## Platforms Affected
|
||
|
|
||
|
Android version 10 (Q) or earlier.
|
||
|
|
||
|
Oboe version 1.4.0 or earlier when using OpenSLES with an OUTPUT stream callback.
|
||
|
|
||
|
OR any version of Oboe if:
|
||
|
* Oboe is using using OpenSL ES or a non-MMAP Legacy AAudio stream
|
||
|
* AND you call stream->getFramesRead() or stream->getTimestamp(...) from inside
|
||
|
an OUTPUT stream callback,
|
||
|
|
||
|
It does **not** happen when Oboe uses AAudio MMAP because it does not call releaseBuffer().
|
||
|
|
||
|
## Workarounds
|
||
|
|
||
|
1. Use Oboe 1.4.1 or later.
|
||
|
1. Do not call stream->getFramesRead() or stream->getTimestamp() from inside the callback of an OUTPUT stream. If you absolutely must, then call them at the beginning of your callback to reduce the probability of a crash.
|
||
|
|
||
|
Here is a [fix in Oboe 1.4.1](https://github.com/google/oboe/pull/863) that removed a call to getPosition().
|
||
|
|
||
|
## Root Cause
|
||
|
|
||
|
The sequence of events is:
|
||
|
1. AudioFlinger AudioTrack obtains a buffer from the audio device
|
||
|
1. user plugs in headphones, which invalidates the audio device
|
||
|
1. app is called (callback) to render audio using the buffer
|
||
|
1. the app or Oboe calls getFramesRead() or getTimestamp(), which calls down to AudioTrack::getPosition() or AudioTrack::getTimestamp()
|
||
|
1. device routing change occurs because the audio device is [invalid](https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/libaudioclient/AudioTrack.cpp;l=1239;drc=48e98cf8dbd9fa212a0e129822929dc40e6c3898)
|
||
|
1. callback ends by releasing the buffer back to a different device
|
||
|
1. AudioTrackShared::releaseBuffer() checks to make sure the device matches the one in ObtainBuffer() and asserts if they do not match.
|
||
|
|
||
|
Oboe, before V1.4.1, would update the server position in its callback. This called getPosition() in OpenSL ES, which called AudioTrack::getPosition().
|
||
|
|
||
|
The probability of the assert() is proportional to the time that the CPU spends between obtaining a buffer and calling restoreTrack_l().
|
||
|
|
||
|
This bug is tracked internally at: b/136268149
|
||
|
|
||
|
## Reproduce the Bug
|
||
|
|
||
|
These steps will trigger the bug most of the time:
|
||
|
|
||
|
1. Install OboeTester 1.5.22 or later, with Oboe < 1.4.1
|
||
|
1. Enter in a Terminal window: adb logcat | grep releaseBuffer
|
||
|
1. Launch OboeTester
|
||
|
1. Click TEST OUTPUT
|
||
|
1. Select API: OpenSL ES
|
||
|
1. Click OPEN
|
||
|
1. Click START, you should hear a tone
|
||
|
1. Slide "Workload" fader slowly up until you hear bad glitches.
|
||
|
1. Plug in headphones.
|
||
|
|
||
|
You may see a message like this in the logcat:
|
||
|
|
||
|
AudioTrackShared: releaseBuffer: mUnreleased out of range, !(stepCount:96 <= mUnreleased:0 <= mFrameCount:480), BufferSizeInFrames:480
|
||
|
|
||
|
# OEM Information
|
||
|
|
||
|
These patches are available in Q AOSP:
|
||
|
1. [AudioTrack](https://android-review.googlesource.com/c/platform/frameworks/av/+/1251871/)
|
||
|
1. [AudioRecord](https://android-review.googlesource.com/c/platform/frameworks/av/+/1251872/)
|