AudioTrack: add setBufferSizeInFrames()
Also add getBufferCapacityInFrames().
These can be used to dynamically raise or lower latency.
Bug: 21019153
Signed-off-by: Phil Burk <philburk@google.com>
Change-Id: I02ca7f6f5cc4e089fcd81cc8a2b6ff234e0381a8
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 5e14940..caf685e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -855,6 +855,31 @@
return mPlaybackRate;
}
+ssize_t AudioTrack::getBufferSizeInFrames()
+{
+ AutoMutex lock(mLock);
+ if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+ return NO_INIT;
+ }
+ return mProxy->getBufferSizeInFrames();
+}
+
+ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
+{
+ AutoMutex lock(mLock);
+ if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+ return NO_INIT;
+ }
+ // Reject if timed track or compressed audio.
+ if (mIsTimed || !audio_is_linear_pcm(mFormat)) {
+ return INVALID_OPERATION;
+ }
+ // TODO also need to inform the server side (through mAudioTrack) that
+ // the buffer count is reduced, otherwise the track may never start
+ // because the server thinks it is never filled.
+ return mProxy->setBufferSizeInFrames(bufferSizeInFrames);
+}
+
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 9fad500..0d43da8 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -66,7 +66,9 @@
ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
size_t frameSize, bool isOut, bool clientInServer)
- : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mEpoch(0)
+ : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
+ , mBufferSizeInFrames(frameCount)
+ , mEpoch(0)
{
}
@@ -151,6 +153,7 @@
rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
front = cblk->u.mStreaming.mFront;
}
+ // write to rear, read from front
ssize_t filled = rear - front;
// pipe should not be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
@@ -166,11 +169,17 @@
cblk->u.mStreaming.mFront = rear;
(void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
}
- // don't allow filling pipe beyond the nominal size
- size_t avail = mIsOut ? mFrameCount - filled : filled;
- if (avail > 0) {
+ // Don't allow filling pipe beyond the user settable size.
+ // The calculation for avail can go negative if the buffer size
+ // is suddenly dropped below the amount already in the buffer.
+ // So use a signed calculation to prevent a numeric overflow abort.
+ ssize_t adjustableSize = (ssize_t) mBufferSizeInFrames;
+ ssize_t avail = (mIsOut) ? adjustableSize - filled : filled;
+ if (avail < 0) {
+ avail = 0;
+ } else if (avail > 0) {
// 'avail' may be non-contiguous, so return only the first contiguous chunk
- size_t part1;
+ ssize_t part1;
if (mIsOut) {
rear &= mFrameCountP2 - 1;
part1 = mFrameCountP2 - rear;
@@ -181,10 +190,10 @@
if (part1 > avail) {
part1 = avail;
}
- if (part1 > buffer->mFrameCount) {
+ if (part1 > (ssize_t) buffer->mFrameCount) {
part1 = buffer->mFrameCount;
}
- buffer->mFrameCount = part1;
+ buffer->mFrameCount = (size_t) part1;
buffer->mRaw = part1 > 0 ?
&((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
buffer->mNonContig = avail - part1;
@@ -347,6 +356,20 @@
(mFrameCountP2 - 1);
}
+size_t ClientProxy::setBufferSizeInFrames(size_t size)
+{
+ // TODO set minimum to 2X the fast mixer buffer size.
+ size_t minimum = 128 * 2; // arbitrary
+ size_t maximum = frameCount();
+ if (size < minimum) {
+ size = minimum;
+ } else if (size > maximum) {
+ size = maximum;
+ }
+ mBufferSizeInFrames = size;
+ return size;
+}
+
// ---------------------------------------------------------------------------
void AudioTrackClientProxy::flush()