summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2013-09-16 18:07:38 -0700
committerGlenn Kasten <gkasten@google.com>2013-09-17 11:24:02 -0700
commitce8828a016b082f730152af2204b8ea3610dc1ec (patch)
treeaad0c32a17516519b22bcea0d4f2fa7c81c61d28 /media
parentd176ec1e371a686c58385692a28da677e398c302 (diff)
downloadframeworks_av-ce8828a016b082f730152af2204b8ea3610dc1ec.zip
frameworks_av-ce8828a016b082f730152af2204b8ea3610dc1ec.tar.gz
frameworks_av-ce8828a016b082f730152af2204b8ea3610dc1ec.tar.bz2
Fix underruns when fast track denied due to SRC
OpenSL ES requests a fast track. If sample rate conversion is needed, the request is denied by server, and a larger client buffer is used to handle the higher latency of a normal track. However the client notification period was calculated based on buffer being divided into 2 sub-buffers. That resulted in the notification period being too long. The server pulls chunks that are smaller than half the total buffer. So now the client uses 3 sub-buffers when there is SRC. Also removed the 'defer wake' optimization because it was incorrect. This optimization attempted to reduce the number of wakeups of client, when server releaseBuffer knows that another releaseBuffer will be following. But there is no way for the first releaseBuffer to predict how soon the second releaseBuffer will occur. In some cases it was a long time, and the client underran. So now the client is woken up immediately if the total number of available frames to client is >= the minimum number the client wants to see (the notification period). Also fix bug where minimum frame count was not being used in the calculation of notification period. Bug: 10342804 Change-Id: I3c246f4e7bc3684a344f2cf08268dc082e338e2a
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/AudioTrack.cpp67
-rw-r--r--media/libmedia/AudioTrackShared.cpp7
2 files changed, 37 insertions, 37 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 744faee..15249a4 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -815,12 +815,29 @@ status_t AudioTrack::createTrack_l(
return NO_INIT;
}
+ // Not all of these values are needed under all conditions, but it is easier to get them all
+
uint32_t afLatency;
- if ((status = AudioSystem::getLatency(output, streamType, &afLatency)) != NO_ERROR) {
+ status = AudioSystem::getLatency(output, streamType, &afLatency);
+ if (status != NO_ERROR) {
ALOGE("getLatency(%d) failed status %d", output, status);
return NO_INIT;
}
+ size_t afFrameCount;
+ status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
+ if (status != NO_ERROR) {
+ ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
+ return NO_INIT;
+ }
+
+ uint32_t afSampleRate;
+ status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
+ if (status != NO_ERROR) {
+ ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status);
+ return NO_INIT;
+ }
+
// Client decides whether the track is TIMED (see below), but can only express a preference
// for FAST. Server will perform additional tests.
if ((flags & AUDIO_OUTPUT_FLAG_FAST) && !(
@@ -836,6 +853,14 @@ status_t AudioTrack::createTrack_l(
}
ALOGV("createTrack_l() output %d afLatency %d", output, afLatency);
+ // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
+ // n = 1 fast track; nBuffering is ignored
+ // n = 2 normal track, no sample rate conversion
+ // n = 3 normal track, with sample rate conversion
+ // (pessimistic; some non-1:1 conversion ratios don't actually need triple-buffering)
+ // n > 3 very high latency or very small notification interval; nBuffering is ignored
+ const uint32_t nBuffering = (sampleRate == afSampleRate) ? 2 : 3;
+
mNotificationFramesAct = mNotificationFramesReq;
if (!audio_is_linear_pcm(format)) {
@@ -844,13 +869,6 @@ status_t AudioTrack::createTrack_l(
// Same comment as below about ignoring frameCount parameter for set()
frameCount = sharedBuffer->size();
} else if (frameCount == 0) {
- size_t afFrameCount;
- status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
- if (status != NO_ERROR) {
- ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType,
- status);
- return NO_INIT;
- }
frameCount = afFrameCount;
}
if (mNotificationFramesAct != frameCount) {
@@ -880,26 +898,13 @@ status_t AudioTrack::createTrack_l(
} else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
// FIXME move these calculations and associated checks to server
- uint32_t afSampleRate;
- status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
- if (status != NO_ERROR) {
- ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType,
- status);
- return NO_INIT;
- }
- size_t afFrameCount;
- status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
- if (status != NO_ERROR) {
- ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
- return NO_INIT;
- }
// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
ALOGV("afFrameCount=%d, minBufCount=%d, afSampleRate=%u, afLatency=%d",
afFrameCount, minBufCount, afSampleRate, afLatency);
- if (minBufCount <= 2) {
- minBufCount = sampleRate == afSampleRate ? 2 : 3;
+ if (minBufCount <= nBuffering) {
+ minBufCount = nBuffering;
}
size_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
@@ -909,18 +914,16 @@ status_t AudioTrack::createTrack_l(
if (frameCount == 0) {
frameCount = minFrameCount;
- }
- // Make sure that application is notified with sufficient margin
- // before underrun
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) {
- mNotificationFramesAct = frameCount/2;
- }
- if (frameCount < minFrameCount) {
+ } else if (frameCount < minFrameCount) {
// not ALOGW because it happens all the time when playing key clicks over A2DP
ALOGV("Minimum buffer size corrected from %d to %d",
frameCount, minFrameCount);
frameCount = minFrameCount;
}
+ // Make sure that application is notified with sufficient margin before underrun
+ if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
+ mNotificationFramesAct = frameCount/nBuffering;
+ }
} else {
// For fast tracks, the frame count calculations and checks are done by server
@@ -1001,8 +1004,8 @@ status_t AudioTrack::createTrack_l(
flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
mFlags = flags;
if (sharedBuffer == 0) {
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) {
- mNotificationFramesAct = frameCount/2;
+ if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
+ mNotificationFramesAct = frameCount/nBuffering;
}
}
}
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index e7abb40..4fd92b2 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -481,7 +481,7 @@ size_t StaticAudioTrackClientProxy::getBufferPosition()
ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
size_t frameSize, bool isOut, bool clientInServer)
: Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
- mAvailToClient(0), mFlush(0), mDeferWake(false)
+ mAvailToClient(0), mFlush(0)
{
}
@@ -559,9 +559,6 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer)
&((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
buffer->mNonContig = availToServer - part1;
mUnreleased = part1;
- // optimization to avoid waking up the client too early
- // FIXME need to test for recording
- mDeferWake = part1 < ask && availToServer >= ask;
return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
}
no_init:
@@ -607,7 +604,7 @@ void ServerProxy::releaseBuffer(Buffer* buffer)
minimum = half;
}
// FIXME AudioRecord wakeup needs to be optimized; it currently wakes up client every time
- if (!mIsOut || (!mDeferWake && mAvailToClient + stepCount >= minimum)) {
+ if (!mIsOut || (mAvailToClient + stepCount >= minimum)) {
ALOGV("mAvailToClient=%u stepCount=%u minimum=%u", mAvailToClient, stepCount, minimum);
int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
if (!(old & CBLK_FUTEX_WAKE)) {