Merge "Fix secondary output under&over run" am: bb3c777e40 am: 6252c394be
am: 8f680d3582
Change-Id: I674fa62c01471433e7316c2aa28d16b81eaafa43
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b6da11e..4b295c9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -810,7 +810,33 @@
continue;
}
- size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount());
+ size_t sourceFrameCount = thread->frameCount() * output.sampleRate
+ / thread->sampleRate();
+ size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate
+ / secondaryThread->sampleRate();
+ // If the secondary output has just been opened, the first secondaryThread write
+ // will not block as it will fill the empty startup buffer of the HAL,
+ // so a second sink buffer needs to be ready for the immediate next blocking write.
+ // Additionally, have a margin of one main thread buffer as the scheduling jitter
+ // can reorder the writes (eg if thread A&B have the same write intervale,
+ // the scheduler could schedule AB...BA)
+ size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
+ // Total secondary output buffer must be at least as the read frames plus
+ // the margin of a few buffers on both sides in case the
+ // threads scheduling has some jitter.
+ // That value should not impact latency as the secondary track is started before
+ // its buffer is full, see frameCountToBeReady.
+ size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
+ // The frameCount should also not be smaller than the secondary thread min frame
+ // count
+ size_t minFrameCount = AudioSystem::calculateMinFrameCount(
+ [&] { Mutex::Autolock _l(secondaryThread->mLock);
+ return secondaryThread->latency_l(); }(),
+ secondaryThread->mNormalFrameCount,
+ secondaryThread->mSampleRate,
+ output.sampleRate,
+ input.speed);
+ frameCount = std::max(frameCount, minFrameCount);
using namespace std::chrono_literals;
auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
@@ -843,7 +869,8 @@
patchRecord->buffer(),
patchRecord->bufferSize(),
outputFlags,
- 0ns /* timeout */);
+ 0ns /* timeout */,
+ frameCountToBeReady);
status = patchTrack->initCheck();
if (status != NO_ERROR) {
ALOGE("Secondary output patchTrack init failed: %d", status);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d0f8b17..1ff03c4 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -74,7 +74,10 @@
uid_t uid,
audio_output_flags_t flags,
track_type type,
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
+ /** default behaviour is to start when there are as many frames
+ * ready as possible (aka. Buffer is full). */
+ size_t frameCountToBeReady = SIZE_MAX);
virtual ~Track();
virtual status_t initCheck() const;
@@ -263,6 +266,8 @@
};
sp<AudioVibrationController> mAudioVibrationController;
sp<os::ExternalVibration> mExternalVibration;
+ /** How many frames should be in the buffer before the track is considered ready */
+ const size_t mFrameCountToBeReady;
private:
void interceptBuffer(const AudioBufferProvider::Buffer& buffer);
@@ -382,7 +387,11 @@
void *buffer,
size_t bufferSize,
audio_output_flags_t flags,
- const Timeout& timeout = {});
+ const Timeout& timeout = {},
+ size_t frameCountToBeReady = 1 /** Default behaviour is to start
+ * as soon as possible to have
+ * the lowest possible latency
+ * even if it might glitch. */);
virtual ~PatchTrack();
size_t framesReady() const override;
@@ -402,5 +411,4 @@
private:
void restartIfDisabled();
-
}; // end of PatchTrack
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index eaefc0a..e4402bd 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -513,7 +513,8 @@
uid_t uid,
audio_output_flags_t flags,
track_type type,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ size_t frameCountToBeReady)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
(sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
(sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
@@ -532,6 +533,7 @@
mVolumeHandler(new media::VolumeHandler(sampleRate)),
mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)),
// mSinkTimestamp
+ mFrameCountToBeReady(frameCountToBeReady),
mFastIndex(-1),
mCachedVolume(1.0),
/* The track might not play immediately after being active, similarly as if its volume was 0.
@@ -832,7 +834,7 @@
auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start);
using namespace std::chrono_literals;
// Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
- ALOGD_IF(spent > 200us, "%s: took %lldus to intercept %zu tracks", __func__,
+ ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
spent.count(), mTeePatches.size());
}
@@ -885,8 +887,12 @@
return true;
}
- if (framesReady() >= mServerProxy->getBufferSizeInFrames() ||
- (mCblk->mFlags & CBLK_FORCEREADY)) {
+ size_t bufferSizeInFrames = mServerProxy->getBufferSizeInFrames();
+ size_t framesToBeReady = std::min(mFrameCountToBeReady, bufferSizeInFrames);
+
+ if (framesReady() >= framesToBeReady || (mCblk->mFlags & CBLK_FORCEREADY)) {
+ ALOGV("%s(%d): consider track ready with %zu/%zu, target was %zu)",
+ __func__, mId, framesReady(), bufferSizeInFrames, framesToBeReady);
mFillingUpStatus = FS_FILLED;
android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);
return true;
@@ -1388,6 +1394,7 @@
void AudioFlinger::PlaybackThread::Track::disable()
{
+ // TODO(b/142394888): the filling status should also be reset to filling
signalClientFlag(CBLK_DISABLED);
}
@@ -1765,12 +1772,14 @@
void *buffer,
size_t bufferSize,
audio_output_flags_t flags,
- const Timeout& timeout)
+ const Timeout& timeout,
+ size_t frameCountToBeReady)
: Track(playbackThread, NULL, streamType,
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH),
+ AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH,
+ AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true),
*playbackThread, timeout)
{
@@ -1863,7 +1872,6 @@
{
mProxy->releaseBuffer(buffer);
restartIfDisabled();
- android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags);
}
void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled()