AudioTrack: fix stall if setBufferSizeInFrames() called before play()
The server was waiting for a full buffer.
But the buffer was only getting partly filled.
So the stream was not starting.
The fix involves having the server look at the adjustable threshold.
Bug: 27505889
Change-Id: I5dbf686413e670dacbbecc9e0f838744e465f44f
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ea8a78e..24784ea 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -177,6 +177,10 @@
// server write-only, client read
ExtendedTimestampQueue::Shared mExtendedTimestampQueue;
+ // This is set by AudioTrack.setBufferSizeInFrames().
+ // A write will not fill the buffer above this limit.
+ volatile uint32_t mBufferSizeInFrames; // effective size of the buffer
+
public:
volatile int32_t mFlags; // combinations of CBLK_*
@@ -312,9 +316,9 @@
return mEpoch;
}
- size_t getBufferSizeInFrames() const { return mBufferSizeInFrames; }
- // See documentation for AudioTrack.setBufferSizeInFrames()
- size_t setBufferSizeInFrames(size_t requestedSize);
+ uint32_t getBufferSizeInFrames() const { return mBufferSizeInFrames; }
+ // See documentation for AudioTrack::setBufferSizeInFrames()
+ uint32_t setBufferSizeInFrames(uint32_t requestedSize);
status_t getTimestamp(ExtendedTimestamp *timestamp) {
if (timestamp == nullptr) {
@@ -329,12 +333,10 @@
mTimestamp.clear();
}
-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:
+ // This is a copy of mCblk->mBufferSizeInFrames
+ uint32_t mBufferSizeInFrames; // effective size of the buffer
+
Modulo<uint32_t> mEpoch;
// The shared buffer contents referred to by the timestamp observer
@@ -518,6 +520,11 @@
mTimestampMutator.push(timestamp);
}
+ // Get dynamic buffer size from the shared control block.
+ uint32_t getBufferSizeInFrames() const {
+ return android_atomic_acquire_load((int32_t *)&mCblk->mBufferSizeInFrames);
+ }
+
protected:
size_t mAvailToClient; // estimated frames available to client prior to releaseBuffer()
int32_t mFlush; // our copy of cblk->u.mStreaming.mFlush, for streaming output only
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 423273d..272b0cd 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -860,7 +860,7 @@
if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
return NO_INIT;
}
- return mProxy->getBufferSizeInFrames();
+ return (ssize_t) mProxy->getBufferSizeInFrames();
}
ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
@@ -873,10 +873,7 @@
if (!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);
+ return (ssize_t) mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
}
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 1d15495..7d7134a 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -46,8 +46,10 @@
}
audio_track_cblk_t::audio_track_cblk_t()
- : mServer(0), mFutex(0), mMinimum(0),
- mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
+ : mServer(0), mFutex(0), mMinimum(0)
+ , mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0)
+ , mBufferSizeInFrames(0)
+ , mFlags(0)
{
memset(&u, 0, sizeof(u));
}
@@ -67,10 +69,10 @@
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)
- , mBufferSizeInFrames(frameCount)
, mEpoch(0)
, mTimestampObserver(&cblk->mExtendedTimestampQueue)
{
+ setBufferSizeInFrames(frameCount);
}
const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
@@ -84,6 +86,26 @@
// order of minutes.
#define MAX_SEC 5
+uint32_t ClientProxy::setBufferSizeInFrames(uint32_t size)
+{
+ // TODO set minimum to 2X the fast mixer buffer size.
+ // The minimum should be greater than zero and less than the size
+ // at which underruns will occur.
+ const uint32_t minimum = 128 * 2; // arbitrary
+ const uint32_t maximum = frameCount();
+ uint32_t clippedSize = size;
+ if (clippedSize < minimum) {
+ clippedSize = minimum;
+ } else if (clippedSize > maximum) {
+ clippedSize = maximum;
+ }
+ // for server to read
+ android_atomic_release_store(clippedSize, (int32_t *)&mCblk->mBufferSizeInFrames);
+ // for client to read
+ mBufferSizeInFrames = clippedSize;
+ return clippedSize;
+}
+
status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
struct timespec *elapsed)
{
@@ -174,7 +196,7 @@
// 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 adjustableSize = (ssize_t) getBufferSizeInFrames();
ssize_t avail = (mIsOut) ? adjustableSize - filled : filled;
if (avail < 0) {
avail = 0;
@@ -357,20 +379,6 @@
(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()
@@ -601,6 +609,7 @@
mAvailToClient(0), mFlush(0), mReleased(0)
, mTimestampMutator(&cblk->mExtendedTimestampQueue)
{
+ cblk->mBufferSizeInFrames = frameCount;
}
status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8b49062..a75ca77 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -617,7 +617,7 @@
return true;
}
- if (framesReady() >= mFrameCount ||
+ if (framesReady() >= mServerProxy->getBufferSizeInFrames() ||
(mCblk->mFlags & CBLK_FORCEREADY)) {
mFillingUpStatus = FS_FILLED;
android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);