Merge "aaudio: write if there is room"
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2ece474..6614e5e 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -653,7 +653,7 @@
// Should we block?
if (timeoutNanoseconds == 0) {
break; // don't block
- } else if (framesLeft > 0) {
+ } else if (wakeTimeNanos != 0) {
if (!mAudioEndpoint.isFreeRunning()) {
// If there is software on the other end of the FIFO then it may get delayed.
// So wake up just a little after we expect it to be ready.
@@ -712,37 +712,38 @@
aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
int32_t adjustedFrames = requestedFrames;
- int32_t actualFrames = 0;
- int32_t maximumSize = getBufferCapacity();
+ const int32_t maximumSize = getBufferCapacity() - mFramesPerBurst;
+ // The buffer size can be set to zero.
+ // This means that the callback may be called when the internal buffer becomes empty.
+ // This will be fine on some devices in ideal circumstances and will result in the
+ // lowest possible latency.
+ // If there are glitches then they should be detected as XRuns and the size can be increased.
+ static const int32_t minimumSize = 0;
// Clip to minimum size so that rounding up will work better.
- if (adjustedFrames < 1) {
- adjustedFrames = 1;
- }
+ adjustedFrames = std::max(minimumSize, adjustedFrames);
- if (adjustedFrames > maximumSize) {
- // Clip to maximum size.
+ // Prevent arithmetic overflow by clipping before we round.
+ if (adjustedFrames >= maximumSize) {
adjustedFrames = maximumSize;
} else {
// Round to the next highest burst size.
int32_t numBursts = (adjustedFrames + mFramesPerBurst - 1) / mFramesPerBurst;
adjustedFrames = numBursts * mFramesPerBurst;
- // Rounding may have gone above maximum.
- if (adjustedFrames > maximumSize) {
- adjustedFrames = maximumSize;
- }
}
- aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(adjustedFrames, &actualFrames);
- if (result < 0) {
- return result;
- } else {
- return (aaudio_result_t) actualFrames;
- }
+ // Clip against the actual size from the endpoint.
+ int32_t actualFrames = 0;
+ mAudioEndpoint.setBufferSizeInFrames(maximumSize, &actualFrames);
+ // actualFrames should be <= maximumSize
+ adjustedFrames = std::min(actualFrames, adjustedFrames);
+
+ mBufferSizeInFrames = adjustedFrames;
+ return (aaudio_result_t) adjustedFrames;
}
int32_t AudioStreamInternal::getBufferSize() const {
- return mAudioEndpoint.getBufferSizeInFrames();
+ return mBufferSizeInFrames;
}
int32_t AudioStreamInternal::getBufferCapacity() const {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 9395416..596d37f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -204,6 +204,9 @@
// Sometimes the hardware is operating with a different channel count from the app.
// Then we require conversion in AAudio.
int32_t mDeviceChannelCount = 0;
+
+ int32_t mBufferSizeInFrames = 0; // local threshold to control latency
+
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index b8ef247..dc9f48c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -167,8 +167,10 @@
ATRACE_INT("aaWrote", framesWritten);
}
+ // Sleep if there is too much data in the buffer.
// Calculate an ideal time to wake up.
- if (wakeTimePtr != nullptr && framesWritten >= 0) {
+ if (wakeTimePtr != nullptr
+ && (mAudioEndpoint.getFullFramesAvailable() >= getBufferSize())) {
// By default wake up a few milliseconds from now. // TODO review
int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
aaudio_stream_state_t state = getState();
@@ -184,14 +186,10 @@
break;
case AAUDIO_STREAM_STATE_STARTED:
{
- // When do we expect the next read burst to occur?
-
- // Calculate frame position based off of the writeCounter because
- // the readCounter might have just advanced in the background,
- // causing us to sleep until a later burst.
- int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
- - mAudioEndpoint.getBufferSizeInFrames();
- wakeTime = mClockModel.convertPositionToTime(nextPosition);
+ // Sleep until the readCounter catches up and we only have
+ // the getBufferSize() frames of data sitting in the buffer.
+ int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() - getBufferSize();
+ wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
}
break;
default: