Issue 3032913: improve AudioTrack recovery time
This issue showed that when an AudioTrack underruns during a too long period
of time and is therefore disabled by audioflinger mixer, it takes an additional
delay of up to 3 seconds to recover.
This fix adds a simple mechanism to recover immediately when the client application
is ready to write data again in the AudioTrack buffer
Also throttle warnings on record overflows
Change-Id: I8b2c71578dd134b9e60a15ee4d91b70f3799cb3d
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 97b8086..8527059 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1856,6 +1856,8 @@
if (--(track->mRetryCount) <= 0) {
LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this);
tracksToRemove->add(track);
+ // indicate to client process that the track was disabled because of underrun
+ cblk->flags |= CBLK_DISABLED_ON;
} else if (mixerStatus != MIXER_TRACKS_READY) {
mixerStatus = MIXER_TRACKS_ENABLED;
}
@@ -2790,7 +2792,7 @@
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
// Force underrun condition to avoid false underrun callback until first data is
- // written to buffer
+ // written to buffer (other flags are cleared)
mCblk->flags = CBLK_UNDERRUN_ON;
} else {
mBuffer = sharedBuffer->pointer();
@@ -2813,7 +2815,7 @@
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
// Force underrun condition to avoid false underrun callback until first data is
- // written to buffer
+ // written to buffer (other flags are cleared)
mCblk->flags = CBLK_UNDERRUN_ON;
mBufferEnd = (uint8_t *)mBuffer + bufferSize;
}
@@ -3794,6 +3796,8 @@
AudioBufferProvider::Buffer buffer;
sp<RecordTrack> activeTrack;
+ nsecs_t lastWarning = 0;
+
// start recording
while (!exitPending()) {
@@ -3935,8 +3939,13 @@
}
// client isn't retrieving buffers fast enough
else {
- if (!mActiveTrack->setOverflow())
- LOGW("RecordThread: buffer overflow");
+ if (!mActiveTrack->setOverflow()) {
+ nsecs_t now = systemTime();
+ if ((now - lastWarning) > kWarningThrottle) {
+ LOGW("RecordThread: buffer overflow");
+ lastWarning = now;
+ }
+ }
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.