Merge "AudioTrack: Add getUnderrunCount()"
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 602e1f3..38adb03 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -325,6 +325,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; }
@@ -818,14 +837,18 @@
audio_io_handle_t mOutput; // returned by AudioSystem::getOutput()
sp<AudioTrackThread> mAudioTrackThread;
+ bool mThreadCanCallJava;
float mVolume[2];
float mSendLevel;
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 fd6a160..770f007 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -203,6 +203,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.
@@ -284,7 +286,7 @@
return mEpoch + mCblk->mServer;
}
- void setEpoch(const Modulo<uint32_t> &epoch) {
+ void setEpoch(const Modulo<uint32_t> &epoch) {
mEpoch = epoch;
}
@@ -304,6 +306,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 31e88c3..a13d53a 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -288,6 +288,8 @@
streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
sessionId, transferType, uid, pid);
+ mThreadCanCallJava = threadCanCallJava;
+
switch (transferType) {
case TRANSFER_DEFAULT:
if (sharedBuffer != 0) {
@@ -356,6 +358,9 @@
if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
}
+ if ((mAttributes.flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
+ flags = (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_FAST);
+ }
}
// these below should probably come from the audioFlinger too...
@@ -856,6 +861,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()) {
@@ -1171,20 +1201,26 @@
}
// Client decides whether the track is TIMED (see below), but can only express a preference
// for FAST. Server will perform additional tests.
- if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ bool useCaseAllowed =
// either of these use cases:
// use case 1: shared buffer
(mSharedBuffer != 0) ||
// use case 2: callback transfer mode
(mTransfer == TRANSFER_CALLBACK) ||
// use case 3: obtain/release mode
- (mTransfer == TRANSFER_OBTAIN)) &&
- // matching sample rate
- (mSampleRate == mAfSampleRate))) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, output %u Hz",
+ (mTransfer == TRANSFER_OBTAIN) ||
+ // use case 4: synchronous write
+ ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+ // sample rates must also match
+ bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate);
+ if (!fastAllowed) {
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d,"
+ "track %u Hz, output %u Hz",
mTransfer, mSampleRate, mAfSampleRate);
- // once denied, do not request again if IAudioTrack is re-created
- mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+ // once denied, do not request again if IAudioTrack is re-created
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+ }
}
// The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
@@ -1255,7 +1291,7 @@
pid_t tid = -1;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
trackFlags |= IAudioFlinger::TRACK_FAST;
- if (mAudioTrackThread != 0) {
+ if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
tid = mAudioTrackThread->getTid();
}
}
@@ -1329,7 +1365,9 @@
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
if (trackFlags & IAudioFlinger::TRACK_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount);
- mAwaitBoost = true;
+ if (!mThreadCanCallJava) {
+ mAwaitBoost = true;
+ }
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
// once denied, do not request again if IAudioTrack is re-created
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 716a614..2742db0 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()