Support bit-perfect PCM playback.
This is part of USB audio improvement. Bit-perfect PCM playback
indicates that the PCM data will be sent as is down to the audio HAL.
When the track is bit-perfect, there will not be volume control
applied in the audio mixer. Only effects without processing or hw
accelerated effects will be allowed to attach to bit-perfect tracks.
Bug: 239435816
Test: manually
Test: atest audiopolicy_tests
Change-Id: I0bad4d7d78d4eaf741754d01bc5422ba15374782
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 7309cad..9cc0ce0 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1021,7 +1021,8 @@
audio_port_handle_t* selectedDeviceId,
audio_port_handle_t* portId,
std::vector<audio_io_handle_t>* secondaryOutputs,
- bool *isSpatialized) {
+ bool *isSpatialized,
+ bool *isBitPerfect) {
if (attr == nullptr) {
ALOGE("%s NULL audio attributes", __func__);
return BAD_VALUE;
@@ -1084,6 +1085,7 @@
*secondaryOutputs = VALUE_OR_RETURN_STATUS(convertContainer<std::vector<audio_io_handle_t>>(
responseAidl.secondaryOutputs, aidl2legacy_int32_t_audio_io_handle_t));
*isSpatialized = responseAidl.isSpatialized;
+ *isBitPerfect = responseAidl.isBitPerfect;
return OK;
}
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 3790000..60b08fa 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -477,6 +477,8 @@
switch (aidl) {
case media::AudioMixerBehavior::DEFAULT:
return AUDIO_MIXER_BEHAVIOR_DEFAULT;
+ case media::AudioMixerBehavior::BIT_PERFECT:
+ return AUDIO_MIXER_BEHAVIOR_BIT_PERFECT;
case media::AudioMixerBehavior::INVALID:
return AUDIO_MIXER_BEHAVIOR_INVALID;
}
@@ -487,6 +489,8 @@
switch (legacy) {
case AUDIO_MIXER_BEHAVIOR_DEFAULT:
return media::AudioMixerBehavior::DEFAULT;
+ case AUDIO_MIXER_BEHAVIOR_BIT_PERFECT:
+ return media::AudioMixerBehavior::BIT_PERFECT;
case AUDIO_MIXER_BEHAVIOR_INVALID:
return media::AudioMixerBehavior::INVALID;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl b/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl
index 0c0c070..38f50d6 100644
--- a/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl
@@ -30,4 +30,8 @@
* different sources.
*/
DEFAULT = 0,
+ /**
+ * The audio data in the mixer will be bit-perfect as long as possible.
+ */
+ BIT_PERFECT = 1,
}
diff --git a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
index 5b25d79..385f787 100644
--- a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
@@ -36,4 +36,5 @@
boolean isSpatialized;
/** The suggested audio config if fails to get an output. **/
AudioConfigBase configBase;
+ boolean isBitPerfect;
}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 507802d..163adcb 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -300,6 +300,7 @@
* @param[out] portId the generated port id to identify the client
* @param[out] secondaryOutputs collection of io handle for secondary outputs
* @param[out] isSpatialized true if the playback will be spatialized
+ * @param[out] isBitPerfect true if the playback will be bit-perfect
* @return if the call is successful or not
*/
static status_t getOutputForAttr(audio_attributes_t *attr,
@@ -312,7 +313,8 @@
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
std::vector<audio_io_handle_t> *secondaryOutputs,
- bool *isSpatialized);
+ bool *isSpatialized,
+ bool *isBitPerfect);
static status_t startOutput(audio_port_handle_t portId);
static status_t stopOutput(audio_port_handle_t portId);
static void releaseOutput(audio_port_handle_t portId);
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index e6fdb1d..c2b82d1 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -297,6 +297,27 @@
return NO_ERROR;
}
+void AudioMixer::Track::unprepareForTee() {
+ ALOGV("AudioMixer::%s", __func__);
+ if (mTeeBufferProvider.get() != nullptr) {
+ mTeeBufferProvider.reset(nullptr);
+ reconfigureBufferProviders();
+ }
+}
+
+status_t AudioMixer::Track::prepareForTee() {
+ ALOGV("AudioMixer::%s(%p) teeBuffer=%p", __func__, this, teeBuffer);
+ unprepareForTee();
+ if (teeBuffer != nullptr) {
+ const size_t frameSize = audio_bytes_per_frame(channelCount + mHapticChannelCount, mFormat);
+ mTeeBufferProvider.reset(new TeeBufferProvider(
+ frameSize, frameSize, kCopyBufferFrameCount,
+ (uint8_t*)teeBuffer, mTeeBufferFrameCount));
+ reconfigureBufferProviders();
+ }
+ return NO_ERROR;
+}
+
void AudioMixer::Track::clearContractedBuffer()
{
if (mAdjustChannelsBufferProvider.get() != nullptr) {
@@ -305,10 +326,20 @@
}
}
+void AudioMixer::Track::clearTeeFrameCopied() {
+ if (mTeeBufferProvider.get() != nullptr) {
+ static_cast<TeeBufferProvider*>(mTeeBufferProvider.get())->clearFramesCopied();
+ }
+}
+
void AudioMixer::Track::reconfigureBufferProviders()
{
// configure from upstream to downstream buffer providers.
bufferProvider = mInputBufferProvider;
+ if (mTeeBufferProvider != nullptr) {
+ mTeeBufferProvider->setBufferProvider(bufferProvider);
+ bufferProvider = mTeeBufferProvider.get();
+ }
if (mAdjustChannelsBufferProvider.get() != nullptr) {
mAdjustChannelsBufferProvider->setBufferProvider(bufferProvider);
bufferProvider = mAdjustChannelsBufferProvider.get();
@@ -420,6 +451,20 @@
track->mHapticMaxAmplitude = hapticMaxAmplitude;
}
} break;
+ case TEE_BUFFER:
+ if (track->teeBuffer != valueBuf) {
+ track->teeBuffer = valueBuf;
+ ALOGV("setParameter(TRACK, TEE_BUFFER, %p)", valueBuf);
+ track->prepareForTee();
+ }
+ break;
+ case TEE_BUFFER_FRAME_COUNT:
+ if (track->mTeeBufferFrameCount != valueInt) {
+ track->mTeeBufferFrameCount = valueInt;
+ ALOGV("setParameter(TRACK, TEE_BUFFER_FRAME_COUNT, %i)", valueInt);
+ track->prepareForTee();
+ }
+ break;
default:
LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
}
@@ -500,6 +545,8 @@
track->mReformatBufferProvider->reset();
} else if (track->mAdjustChannelsBufferProvider.get() != nullptr) {
track->mAdjustChannelsBufferProvider->reset();
+ } else if (track->mTeeBufferProvider.get() != nullptr) {
+ track->mTeeBufferProvider->reset();
}
track->mInputBufferProvider = bufferProvider;
@@ -565,6 +612,7 @@
if (t->mKeepContractedChannels) {
t->clearContractedBuffer();
}
+ t->clearTeeFrameCopied();
}
}
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index f30eb54..fd06991 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -143,6 +143,7 @@
// setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
t->mainBuffer = NULL;
t->auxBuffer = NULL;
+ t->teeBuffer = nullptr;
t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
t->mFormat = format;
t->mMixerInFormat = kUseFloat && kUseNewMixer ?
@@ -150,6 +151,7 @@
t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
+ t->mTeeBufferFrameCount = 0;
status_t status = postCreateTrack(t.get());
if (status != OK) return status;
mTracks[name] = t;
@@ -401,6 +403,20 @@
invalidate();
}
} break;
+ case TEE_BUFFER:
+ if (track->teeBuffer != valueBuf) {
+ track->teeBuffer = valueBuf;
+ ALOGV("setParameter(TRACK, TEE_BUFFER, %p)", valueBuf);
+ invalidate();
+ }
+ break;
+ case TEE_BUFFER_FRAME_COUNT:
+ if (track->mTeeBufferFrameCount != valueInt) {
+ track->mTeeBufferFrameCount = valueInt;
+ ALOGV("setParameter(TRACK, TEE_BUFFER_FRAME_COUNT, %i)", valueInt);
+ invalidate();
+ }
+ break;
default:
LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
}
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 4658db8..a9944fb 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -739,5 +739,21 @@
mContractedWrittenFrames = 0;
CopyBufferProvider::reset();
}
+
+void TeeBufferProvider::copyFrames(void *dst, const void *src, size_t frames) {
+ memcpy(dst, src, frames * mInputFrameSize);
+ if (int teeBufferFrameLeft = mTeeBufferFrameCount - mFrameCopied; teeBufferFrameLeft < frames) {
+ ALOGW("Unable to copy all frames to tee buffer, %d frames dropped",
+ (int)frames - teeBufferFrameLeft);
+ frames = teeBufferFrameLeft;
+ }
+ memcpy(mTeeBuffer + mFrameCopied * mInputFrameSize, src, frames * mInputFrameSize);
+ mFrameCopied += frames;
+}
+
+void TeeBufferProvider::clearFramesCopied() {
+ mFrameCopied = 0;
+}
+
// ----------------------------------------------------------------------------
} // namespace android
diff --git a/media/libaudioprocessing/include/media/AudioMixer.h b/media/libaudioprocessing/include/media/AudioMixer.h
index 2993a60..b39fb92 100644
--- a/media/libaudioprocessing/include/media/AudioMixer.h
+++ b/media/libaudioprocessing/include/media/AudioMixer.h
@@ -96,7 +96,10 @@
void unprepareForReformat();
status_t prepareForAdjustChannels(size_t frames);
void unprepareForAdjustChannels();
+ void unprepareForTee();
+ status_t prepareForTee();
void clearContractedBuffer();
+ void clearTeeFrameCopied();
bool setPlaybackRate(const AudioPlaybackRate &playbackRate);
void reconfigureBufferProviders();
@@ -108,20 +111,22 @@
* all pre-mixer track buffer conversions outside the AudioMixer class.
*
* 1) mInputBufferProvider: The AudioTrack buffer provider.
- * 2) mAdjustChannelsBufferProvider: Expands or contracts sample data from one interleaved
+ * 2) mTeeBufferProvider: If not NULL, copy the data to tee buffer.
+ * 3) mAdjustChannelsBufferProvider: Expands or contracts sample data from one interleaved
* channel format to another. Expanded channels are filled with zeros and put at the end
* of each audio frame. Contracted channels are copied to the end of the buffer.
- * 3) mReformatBufferProvider: If not NULL, performs the audio reformat to
+ * 4) mReformatBufferProvider: If not NULL, performs the audio reformat to
* match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
* requires reformat. For example, it may convert floating point input to
* PCM_16_bit if that's required by the downmixer.
- * 4) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match
+ * 5) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match
* the number of channels required by the mixer sink.
- * 5) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
+ * 6) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
* the downmixer requirements to the mixer engine input requirements.
- * 6) mTimestretchBufferProvider: Adds timestretching for playback rate
+ * 7) mTimestretchBufferProvider: Adds timestretching for playback rate
*/
AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider.
+ std::unique_ptr<PassthruBufferProvider> mTeeBufferProvider;
std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
std::unique_ptr<PassthruBufferProvider> mDownmixerBufferProvider;
diff --git a/media/libaudioprocessing/include/media/AudioMixerBase.h b/media/libaudioprocessing/include/media/AudioMixerBase.h
index 3419816..caccb6a 100644
--- a/media/libaudioprocessing/include/media/AudioMixerBase.h
+++ b/media/libaudioprocessing/include/media/AudioMixerBase.h
@@ -68,6 +68,10 @@
// 0x4004 reserved
MIXER_FORMAT = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
+ // 0x4007, 0x4008, 0x4009 is defined for haptic stuff in AudioMixer.h
+ TEE_BUFFER = 0x400A,
+ TEE_BUFFER_FORMAT = 0x400B,
+ TEE_BUFFER_FRAME_COUNT = 0x400C,
// for target RESAMPLE
SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name;
// parameter 'value' is the new sample rate in Hz.
@@ -271,6 +275,7 @@
uint32_t sampleRate;
int32_t* mainBuffer;
int32_t* auxBuffer;
+ int32_t* teeBuffer;
int32_t sessionId;
@@ -290,6 +295,8 @@
audio_channel_mask_t mMixerChannelMask;
uint32_t mMixerChannelCount;
+ int32_t mTeeBufferFrameCount;
+
protected:
// hooks
diff --git a/media/libaudioprocessing/include/media/BufferProviders.h b/media/libaudioprocessing/include/media/BufferProviders.h
index b3ab8a5..7a41002 100644
--- a/media/libaudioprocessing/include/media/BufferProviders.h
+++ b/media/libaudioprocessing/include/media/BufferProviders.h
@@ -279,6 +279,27 @@
size_t mContractedWrittenFrames;
size_t mContractedOutputFrameSize; // contracted output frame size
};
+
+class TeeBufferProvider : public CopyBufferProvider {
+public:
+ TeeBufferProvider(
+ size_t inputFrameSize, size_t outputFrameSize,
+ size_t bufferFrameCount, uint8_t* teeBuffer, int teeBufferFrameCount)
+ : CopyBufferProvider(inputFrameSize, outputFrameSize, bufferFrameCount),
+ mTeeBuffer(teeBuffer), mTeeBufferFrameCount(teeBufferFrameCount),
+ mFrameCopied(0) {};
+
+ void copyFrames(void *dst, const void *src, size_t frames) override;
+
+ void clearFramesCopied();
+
+protected:
+ AudioBufferProvider *mTrackBufferProvider;
+ uint8_t* mTeeBuffer;
+ const int mTeeBufferFrameCount;
+ int mFrameCopied;
+};
+
// ----------------------------------------------------------------------------
} // namespace android