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/include/media/AudioTrack.h b/include/media/AudioTrack.h
index fe4611c..69831bc 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -320,6 +320,25 @@
uint32_t channelCount() const { return mChannelCount; }
size_t frameCount() const { return mFrameCount; }
+ /* Return effective size of audio buffer that an application writes to
+ * or a negative error if the track is uninitialized.
+ */
+ ssize_t getBufferSizeInFrames();
+
+ /* Set the effective size of audio buffer that an application writes to.
+ * This is used to determine the amount of available room in the buffer,
+ * which determines when a write will block.
+ * This allows an application to raise and lower the audio latency.
+ * The requested size may be adjusted so that it is
+ * greater or equal to the absolute minimum and
+ * less than or equal to the getBufferCapacityInFrames().
+ * It may also be adjusted slightly for internal reasons.
+ *
+ * Return the final size or a negative error if the track is unitialized
+ * or does not support variable sizes.
+ */
+ ssize_t setBufferSizeInFrames(size_t size);
+
/* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
@@ -817,8 +836,11 @@
mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it
uint32_t mOriginalSampleRate;
AudioPlaybackRate mPlaybackRate;
- size_t mFrameCount; // corresponds to current IAudioTrack, value is
- // reported back by AudioFlinger to the client
+
+ // Corresponds to current IAudioTrack, value is reported back by AudioFlinger to the client.
+ // This allocated buffer size is maintained by the proxy.
+ size_t mFrameCount; // maximum size of buffer
+
size_t mReqFrameCount; // frame count to request the first or next time
// a new IAudioTrack is needed, non-decreasing
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index e458f3c..68d27bb 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -204,6 +204,8 @@
size_t mNonContig; // number of additional non-contiguous frames available
};
+ size_t frameCount() const { return mFrameCount; }
+
protected:
// These refer to shared memory, and are virtual addresses with respect to the current process.
// They may have different virtual addresses within the other process.
@@ -285,7 +287,7 @@
return mEpoch + mCblk->mServer;
}
- void setEpoch(const Modulo<uint32_t> &epoch) {
+ void setEpoch(const Modulo<uint32_t> &epoch) {
mEpoch = epoch;
}
@@ -305,6 +307,15 @@
return mEpoch;
}
+ size_t getBufferSizeInFrames() const { return mBufferSizeInFrames; }
+ // See documentation for AudioTrack.setBufferSizeInFrames()
+ size_t setBufferSizeInFrames(size_t requestedSize);
+
+protected:
+ // This is set by AudioTrack.setBufferSizeInFrames().
+ // A write will not fill the buffer above this limit.
+ size_t mBufferSizeInFrames; // effective size of the buffer
+
private:
Modulo<uint32_t> mEpoch;
};
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()