FuguAudio: improve buffer sizing for AC3 and DTS passthrough
Set framesPerChunk to a multiple of 512 if the data is being
written to the HAL in multiples of 512.
This helps reduce the number of retrograde timestamps and
spontaneous device shutdowns.
Bug: 19938315
Change-Id: Ib1e742130f31d029a4008149aa390d520706bd74
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/libaudio/AudioStreamOut.cpp b/libaudio/AudioStreamOut.cpp
index 93cce95..18dbbe5 100644
--- a/libaudio/AudioStreamOut.cpp
+++ b/libaudio/AudioStreamOut.cpp
@@ -39,6 +39,7 @@
AudioStreamOut::AudioStreamOut(AudioHardwareOutput& owner, bool mcOut)
: mRenderPosition(0)
, mPresentationPosition(0)
+ , mLastTimestampPosition(0)
, mOwnerHAL(owner)
, mFramesWritten(0)
, mTgtDevices(0)
@@ -51,13 +52,13 @@
mPhysOutputs.setCapacity(3);
- // Set some reasonable defaults for these. All of this should be eventually
+ // Set some reasonable defaults for these. All of this should eventually
// be overwritten by a specific audio flinger configuration, but it does not
// hurt to have something here by default.
mInputSampleRate = 48000;
mInputChanMask = AUDIO_CHANNEL_OUT_STEREO;
mInputFormat = AUDIO_FORMAT_PCM_16_BIT;
- mInputNominalChunksInFlight = 4;
+ mInputNominalChunksInFlight = 4; // pcm_open() fails if not 4!
updateInputNums();
mThrottleValid = false;
@@ -179,59 +180,14 @@
{
assert(mLocalClock.initCheck());
- // mInputBufSize determines how many audio frames AudioFlinger is going to
- // mix at a time. We also use the mInputBufSize to determine the ALSA
- // period_size, the number of of samples which need to play out (at most)
- // before low level ALSA driver code is required to wake up upper levels of
- // SW to fill a new buffer. As it turns out, ALSA is going to apply some
- // rules and modify the period_size which we pass to it. One of the things
- // ALSA seems to do is attempt to round the period_size up to a value which
- // will make the period an integral number of 0.5 mSec. This round-up
- // behavior can cause the low levels of ALSA to consume more data per period
- // than the AudioFlinger mixer has been told to produce. If there are only
- // two buffers in flight at any given point in time, this can lead to a
- // situation where the pipeline ends up slipping an extra buffer and
- // underflowing. There are two approaches to mitigate this, both of which
- // are implemented in this HAL...
- //
- // 1) Try as hard as possible to make certain that the buffer size we choose
- // results in a period_size which is not going to get rounded up by ALSA.
- // This means that we want a buffer size which at the chosen sample rate
- // and frame size will be an integral multiple of 1/2 mSec.
- // 2) Increate the number of chunks we keep in flight. If the system slips
- // a single period, its only really a problem if there is no data left in
- // the pipeline waiting to be played out. The mixer should going to mix
- // as fast as possible until the buffer has been topped off. By
- // decreasing the buffer size and increasing the number of buffers in
- // flight, we increase the number of interrups and mix events per second,
- // but buy ourselves some insurance against the negative side effects of
- // slipping one buffer in the schedule. We end up using 4 buffers at
- // 10mSec, making the total audio latency somewhere between 40 and 50
- // mSec, depending on when a sample begins playback relative to
- // AudioFlinger's mixing schedule.
- //
mInputChanCount = audio_channel_count_from_out_mask(mInputChanMask);
- // Picking a chunk duration 10mSec should satisfy #1 for both major families
- // of audio sample rates (the 44.1K and 48K families). In the case of 44.1
- // (or higher) we will end up with a multiple of 441 frames of audio per
- // chunk, while for 48K, we will have a multiple of 480 frames of audio per
- // chunk. This will not work well for lower sample rates in the 44.1 family
- // (22.05K and 11.025K); it is unlikely that we will ever be configured to
- // deliver those rates, and if we ever do, we will need to rely on having
- // extra chunks in flight to deal with the jitter problem described above.
- mInputChunkFrames = outputSampleRate() / 100;
+ // We found by experimentation that a buffer size that was a multiple of 512
+ // prevented some problems with retrograde results from get_presentation_position().
+ // It also prevents some spontaneous shutdowns of the output device.
+ mInputChunkFrames = 512 * ((outputSampleRate() + 48000 - 1) / 48000);
- // FIXME: Currently, audio flinger demands an input buffer size which is a
- // multiple of 16 audio frames. Right now, there is no good way to
- // reconcile this with ALSA round-up behavior described above when the
- // desired sample rate is a member of the 44.1 family. For now, we just
- // round up to the nearest multiple of 16 frames and roll the dice, but
- // someday it would be good to fix one or the other halves of the problem
- // (either ALSA or AudioFlinger)
- mInputChunkFrames = (mInputChunkFrames + 0xF) & ~0xF;
-
- ALOGD("AudioStreamOut::updateInputNums: chunk size %u from output rate %u\n",
+ ALOGI("updateInputNums: chunk size %u from output rate %u\n",
mInputChunkFrames, outputSampleRate());
mInputFrameSize = mInputChanCount * audio_bytes_per_sample(mInputFormat);
@@ -424,7 +380,16 @@
ALOGI("getPresentationPosition, %lld, %4u, %lld, %llu",
mPresentationPosition, avail, signedFrames, nanos);
#endif
- *frames = (uint64_t) signedFrames;
+ uint64_t unsignedFrames = (uint64_t) signedFrames;
+ *frames = unsignedFrames;
+
+ // Log retrograde timestamps to help debug driver.
+ if (unsignedFrames < mLastTimestampPosition) {
+ ALOGW("getPresentationPosition: retrograde timestamp, diff = %d",
+ (int32_t)(mLastTimestampPosition - unsignedFrames));
+ }
+ mLastTimestampPosition = unsignedFrames;
+
result = NO_ERROR;
}
} else {
@@ -522,7 +487,7 @@
if (newOutput != NULL) {
// If we actually got an output, go ahead and add it to our list
// of physical outputs. The rest of the system will handle
- // starting it up. If we didn't get an output, but also go no
+ // starting it up. If we didn't get an output, but also got no
// error code, it just means that the output is currently busy
// and should become available soon.
ALOGI("updateTargetOutputs: adding output back to mPhysOutputs");
diff --git a/libaudio/AudioStreamOut.h b/libaudio/AudioStreamOut.h
index a24bc71..1e159c1 100644
--- a/libaudio/AudioStreamOut.h
+++ b/libaudio/AudioStreamOut.h
@@ -75,6 +75,7 @@
// Track frame position for timestamps, etc.
uint64_t mRenderPosition;
uint64_t mPresentationPosition;
+ uint64_t mLastTimestampPosition;
// Our HAL, used as the middle-man to collect and trade AudioOutputs.
AudioHardwareOutput& mOwnerHAL;