audioflinger: Add support for RecordTrack with no conversion
When piping encoded audio data via software patch, it needs
to be created without the buffer converter. In this case the audio
data is copied directly from ResamplerBufferProvider.
Added input flag AUDIO_INPUT_FLAG_DIRECT to indicate to PatchPanel
that the PatchRecord track needs to be opened in this mode.
This flag can be later added to minor Audio HAL update.
Bug: 63901775
Test: MSD scenario; verified that phone over USB headset still works
on marlin / sailfish
Change-Id: If2745778d356769b143fb3c29910275ddef119ac
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index a3db754..514c795 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -132,6 +132,7 @@
MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_MMAP_NOIRQ),
MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_VOIP_TX),
MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_AV_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_DIRECT),
TERMINATOR
};
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 13477f3..53a4ce9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2335,6 +2335,9 @@
return 0;
}
+ // Some flags are specific to framework and must not leak to the HAL.
+ flags = static_cast<audio_input_flags_t>(flags & ~AUDIO_INPUT_FRAMEWORK_FLAGS);
+
// Audio Policy can request a specific handle for hardware hotword.
// The goal here is not to re-open an already opened input.
// It is to use a pre-assigned I/O handle.
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 241af09..968d5aa 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -40,6 +40,7 @@
audio_session_t triggerSession);
virtual void stop();
virtual bool isFastTrack() const { return false; }
+ bool isDirect() const override { return true; }
void appendDumpHeader(String8& result);
void appendDump(String8& result, bool active);
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index c2927ba..42a5a90 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -423,6 +423,14 @@
uint32_t sampleRate = mPlayback.thread()->sampleRate();
audio_format_t format = mPlayback.thread()->format();
+ audio_format_t inputFormat = mRecord.thread()->format();
+ if (!audio_is_linear_pcm(inputFormat)) {
+ // The playbackThread format will say PCM for IEC61937 packetized stream.
+ // Use recordThread format.
+ format = inputFormat;
+ }
+ audio_input_flags_t inputFlags = mAudioPatch.sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+ mAudioPatch.sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;
sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
mRecord.thread().get(),
sampleRate,
@@ -431,12 +439,15 @@
frameCount,
NULL,
(size_t)0 /* bufferSize */,
- AUDIO_INPUT_FLAG_NONE);
+ inputFlags);
status = mRecord.checkTrack(tempRecordTrack.get());
if (status != NO_ERROR) {
return status;
}
+ audio_output_flags_t outputFlags = mAudioPatch.sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+ mAudioPatch.sinks[0].flags.output : AUDIO_OUTPUT_FLAG_NONE;
+
// 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(
@@ -448,7 +459,7 @@
frameCount,
tempRecordTrack->buffer(),
tempRecordTrack->bufferSize(),
- AUDIO_OUTPUT_FLAG_NONE);
+ outputFlags);
status = mPlayback.checkTrack(tempPatchTrack.get());
if (status != NO_ERROR) {
return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index a93899b..4d5f6b0 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -71,7 +71,8 @@
}
bool isOffloaded() const
{ return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
- bool isDirect() const { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
+ bool isDirect() const override
+ { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
bool isOffloadedOrDirect() const { return (mFlags
& (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
| AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 43b6391..b0c9fda 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -63,6 +63,8 @@
const ExtendedTimestamp ×tamp);
virtual bool isFastTrack() const { return (mFlags & AUDIO_INPUT_FLAG_FAST) != 0; }
+ bool isDirect() const override
+ { return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; }
void setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; }
bool isSilenced() const { return mSilenced; }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6220bbf..85e84f4 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6815,9 +6815,33 @@
framesOut = min(framesOut,
destinationFramesPossible(
framesIn, mSampleRate, activeTrack->mSampleRate));
- // process frames from the RecordThread buffer provider to the RecordTrack buffer
- framesOut = activeTrack->mRecordBufferConverter->convert(
- activeTrack->mSink.raw, activeTrack->mResamplerBufferProvider, framesOut);
+
+ if (activeTrack->isDirect()) {
+ // No RecordBufferConverter used for compressed formats. Pass
+ // straight from RecordThread buffer to RecordTrack buffer.
+ AudioBufferProvider::Buffer buffer;
+ buffer.frameCount = framesOut;
+ status_t status = activeTrack->mResamplerBufferProvider->getNextBuffer(&buffer);
+ if (status == OK && buffer.frameCount != 0) {
+ ALOGV_IF(buffer.frameCount != framesOut,
+ "%s() read less than expected (%zu vs %zu)",
+ __func__, buffer.frameCount, framesOut);
+ framesOut = buffer.frameCount;
+ memcpy(activeTrack->mSink.raw, buffer.raw, buffer.frameCount);
+ activeTrack->mResamplerBufferProvider->releaseBuffer(&buffer);
+ } else {
+ framesOut = 0;
+ ALOGE("%s() cannot fill request, status: %d, frameCount: %zu",
+ __func__, status, buffer.frameCount);
+ }
+ } else {
+ // process frames from the RecordThread buffer provider to the RecordTrack
+ // buffer
+ framesOut = activeTrack->mRecordBufferConverter->convert(
+ activeTrack->mSink.raw,
+ activeTrack->mResamplerBufferProvider,
+ framesOut);
+ }
if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) {
overrun = OVERRUN_FALSE;
@@ -7189,8 +7213,10 @@
// see previously buffered data before it called start(), but with greater risk of overrun.
recordTrack->mResamplerBufferProvider->reset();
- // clear any converter state as new data will be discontinuous
- recordTrack->mRecordBufferConverter->reset();
+ if (!recordTrack->isDirect()) {
+ // clear any converter state as new data will be discontinuous
+ recordTrack->mRecordBufferConverter->reset();
+ }
recordTrack->mState = TrackBase::STARTING_2;
// signal thread to start
mWaitWorkCV.broadcast();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index dafba1e..95da9d7 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -91,6 +91,7 @@
void* buffer() const { return mBuffer; }
size_t bufferSize() const { return mBufferSize; }
virtual bool isFastTrack() const = 0;
+ virtual bool isDirect() const = 0;
bool isOutputTrack() const { return (mType == TYPE_OUTPUT); }
bool isPatchTrack() const { return (mType == TYPE_PATCH); }
bool isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f6c33e2..22e610e 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1694,18 +1694,20 @@
return;
}
- mRecordBufferConverter = new RecordBufferConverter(
- thread->mChannelMask, thread->mFormat, thread->mSampleRate,
- channelMask, format, sampleRate);
- // Check if the RecordBufferConverter construction was successful.
- // If not, don't continue with construction.
- //
- // NOTE: It would be extremely rare that the record track cannot be created
- // for the current device, but a pending or future device change would make
- // the record track configuration valid.
- if (mRecordBufferConverter->initCheck() != NO_ERROR) {
- ALOGE("RecordTrack unable to create record buffer converter");
- return;
+ if (!isDirect()) {
+ mRecordBufferConverter = new RecordBufferConverter(
+ thread->mChannelMask, thread->mFormat, thread->mSampleRate,
+ channelMask, format, sampleRate);
+ // Check if the RecordBufferConverter construction was successful.
+ // If not, don't continue with construction.
+ //
+ // NOTE: It would be extremely rare that the record track cannot be created
+ // for the current device, but a pending or future device change would make
+ // the record track configuration valid.
+ if (mRecordBufferConverter->initCheck() != NO_ERROR) {
+ ALOGE("RecordTrack unable to create record buffer converter");
+ return;
+ }
}
mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,