Use fast mode with patch track and patch record if possible.
Use fast mode with patch track/patch record if fast mixer/fast capture
is enabled. With the fast track and fast mixer/fast capture, we can get
a better performance on latency.
Bug: 111800664
Test: make phone call on marlin/walleye with enabling legacy usb hal
Change-Id: I0edd5978049e7c55da217a7a19e45fcbe5c3ac62
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index d063772..dd84bf2 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "Configuration.h"
+#include <audio_utils/format.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <media/AudioBufferProvider.h>
@@ -161,7 +162,21 @@
const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
const FastCaptureState::Command command = mCommand;
- const size_t frameCount = current->mFrameCount;
+ size_t frameCount = current->mFrameCount;
+ AudioBufferProvider* fastPatchRecordBufferProvider = current->mFastPatchRecordBufferProvider;
+ AudioBufferProvider::Buffer patchBuffer;
+
+ if (fastPatchRecordBufferProvider != 0) {
+ patchBuffer.frameCount = ~0;
+ status_t status = fastPatchRecordBufferProvider->getNextBuffer(&patchBuffer);
+ if (status != NO_ERROR) {
+ frameCount = 0;
+ } else if (patchBuffer.frameCount < frameCount) {
+ // TODO: Make sure that it doesn't cause any issues if we just get a small available
+ // buffer from the buffer provider.
+ frameCount = patchBuffer.frameCount;
+ }
+ }
if ((command & FastCaptureState::READ) /*&& isWarm*/) {
ALOG_ASSERT(mInputSource != NULL);
@@ -176,6 +191,7 @@
mTotalNativeFramesRead += framesRead;
dumpState->mFramesRead = mTotalNativeFramesRead;
mReadBufferState = framesRead;
+ patchBuffer.frameCount = framesRead;
} else {
dumpState->mReadErrors++;
mReadBufferState = 0;
@@ -193,11 +209,18 @@
}
if (mReadBufferState > 0) {
ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
- // FIXME This supports at most one fast capture client.
- // To handle multiple clients this could be converted to an array,
- // or with a lot more work the control block could be shared by all clients.
audio_track_cblk_t* cblk = current->mCblk;
- if (cblk != NULL && framesWritten > 0) {
+ if (fastPatchRecordBufferProvider != 0) {
+ // This indicates the fast track is a patch record, update the cblk by
+ // calling releaseBuffer().
+ memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
+ mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
+ patchBuffer.frameCount = framesWritten;
+ fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
+ } else if (cblk != NULL && framesWritten > 0) {
+ // FIXME This supports at most one fast capture client.
+ // To handle multiple clients this could be converted to an array,
+ // or with a lot more work the control block could be shared by all clients.
int32_t rear = cblk->u.mStreaming.mRear;
android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
cblk->mServer += framesWritten;
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
index 9bca2d4..d287232 100644
--- a/services/audioflinger/FastCaptureState.h
+++ b/services/audioflinger/FastCaptureState.h
@@ -18,6 +18,7 @@
#define ANDROID_AUDIO_FAST_CAPTURE_STATE_H
#include <media/nbaio/NBAIO.h>
+#include <media/AudioBufferProvider.h>
#include "FastThreadState.h"
#include <private/media/AudioTrackShared.h>
@@ -37,6 +38,10 @@
size_t mFrameCount; // number of frames per fast capture buffer
audio_track_cblk_t* mCblk; // control block for the single fast client, or NULL
+ audio_format_t mFastPatchRecordFormat = AUDIO_FORMAT_INVALID;
+ AudioBufferProvider* mFastPatchRecordBufferProvider = nullptr; // a reference to a patch
+ // record in fast mode
+
// Extends FastThreadState::Command
static const Command
// The following commands also process configuration changes, and can be "or"ed:
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index f044fb7..ada8572 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -431,14 +431,14 @@
// use a pseudo LCM between input and output framecount
size_t playbackFrameCount = mPlayback.thread()->frameCount();
int playbackShift = __builtin_ctz(playbackFrameCount);
- size_t recordFramecount = mRecord.thread()->frameCount();
- int shift = __builtin_ctz(recordFramecount);
+ size_t recordFrameCount = mRecord.thread()->frameCount();
+ int shift = __builtin_ctz(recordFrameCount);
if (playbackShift < shift) {
shift = playbackShift;
}
- size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
- ALOGV("%s() playframeCount %zu recordFramecount %zu frameCount %zu",
- __func__, playbackFrameCount, recordFramecount, frameCount);
+ size_t frameCount = (playbackFrameCount * recordFrameCount) >> shift;
+ ALOGV("%s() playframeCount %zu recordFrameCount %zu frameCount %zu",
+ __func__, playbackFrameCount, recordFrameCount, frameCount);
// create a special record track to capture from record thread
uint32_t channelCount = mPlayback.thread()->channelCount();
@@ -455,6 +455,17 @@
}
audio_input_flags_t inputFlags = mAudioPatch.sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
mAudioPatch.sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;
+ if (sampleRate == mRecord.thread()->sampleRate() &&
+ inChannelMask == mRecord.thread()->channelMask() &&
+ mRecord.thread()->fastTrackAvailable() &&
+ mRecord.thread()->hasFastCapture()) {
+ // Create a fast track if the record thread has fast capture to get better performance.
+ // Only enable fast mode when there is no resample needed.
+ inputFlags = (audio_input_flags_t) (inputFlags | AUDIO_INPUT_FLAG_FAST);
+ } else {
+ // Fast mode is not available in this case.
+ inputFlags = (audio_input_flags_t) (inputFlags & ~AUDIO_INPUT_FLAG_FAST);
+ }
sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
mRecord.thread().get(),
sampleRate,
@@ -476,6 +487,11 @@
// "reuse one existing output mix" case
streamType = mAudioPatch.sources[1].ext.mix.usecase.stream;
}
+ if (mPlayback.thread()->hasFastMixer()) {
+ // Create a fast track if the playback thread has fast mixer to get better performance.
+ outputFlags = (audio_output_flags_t) (outputFlags | AUDIO_OUTPUT_FLAG_FAST);
+ }
+
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1e411c7..68c8cac 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6700,6 +6700,14 @@
}
didModify = true;
}
+ AudioBufferProvider* abp = (fastTrack != 0 && fastTrack->isPatchTrack()) ?
+ reinterpret_cast<AudioBufferProvider*>(fastTrack.get()) : nullptr;
+ if (state->mFastPatchRecordBufferProvider != abp) {
+ state->mFastPatchRecordBufferProvider = abp;
+ state->mFastPatchRecordFormat = fastTrack == 0 ?
+ AUDIO_FORMAT_INVALID : fastTrack->format();
+ didModify = true;
+ }
sq->end(didModify);
if (didModify) {
sq->push(block);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 847a9c6..23ab37b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1527,6 +1527,8 @@
void updateMetadata_l() override;
+ bool fastTrackAvailable() const { return mFastTrackAvail; }
+
private:
// Enter standby if not already in standby, and set mStandby flag
void standbyIfNotAlreadyInStandby();