Dup first haptic channel to the second when it is not provided.
In this CL, if the device supports two haptic channels while the app
only provides one, the second haptic channel will be duplicating the
first haptic channel. With this change, it can help the users to get
benefit from two haptic channels when it is supported.
Bug: 203725447
Test: atest SoundPoolHapticTest
Test: play single and dual haptic channels
Test: audio smoke test
Change-Id: I6d54b65a5e48b9b49f5464523542aa4cc6a9efa3
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 6d31c12..0114355 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -630,7 +630,8 @@
AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(
audio_format_t format, size_t inChannelCount, size_t outChannelCount,
- size_t frameCount, audio_format_t contractedFormat, void* contractedBuffer) :
+ size_t frameCount, audio_format_t contractedFormat, void* contractedBuffer,
+ size_t contractedOutChannelCount) :
CopyBufferProvider(
audio_bytes_per_frame(inChannelCount, format),
audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
@@ -640,15 +641,22 @@
mOutChannelCount(outChannelCount),
mSampleSizeInBytes(audio_bytes_per_sample(format)),
mFrameCount(frameCount),
- mContractedChannelCount(inChannelCount - outChannelCount),
- mContractedFormat(contractedFormat),
+ mContractedFormat(inChannelCount > outChannelCount
+ ? contractedFormat : AUDIO_FORMAT_INVALID),
+ mContractedInChannelCount(inChannelCount > outChannelCount
+ ? inChannelCount - outChannelCount : 0),
+ mContractedOutChannelCount(contractedOutChannelCount),
+ mContractedSampleSizeInBytes(audio_bytes_per_sample(contractedFormat)),
+ mContractedInputFrameSize(mContractedInChannelCount * mContractedSampleSizeInBytes),
mContractedBuffer(contractedBuffer),
mContractedWrittenFrames(0)
{
- ALOGV("AdjustChannelsBufferProvider(%p)(%#x, %zu, %zu, %zu, %#x, %p)", this, format,
- inChannelCount, outChannelCount, frameCount, contractedFormat, contractedBuffer);
+ ALOGV("AdjustChannelsBufferProvider(%p)(%#x, %zu, %zu, %zu, %#x, %p, %zu)",
+ this, format, inChannelCount, outChannelCount, frameCount, contractedFormat,
+ contractedBuffer, contractedOutChannelCount);
if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
- mContractedFrameSize = audio_bytes_per_frame(mContractedChannelCount, mContractedFormat);
+ mContractedOutputFrameSize =
+ audio_bytes_per_frame(mContractedOutChannelCount, mContractedFormat);
}
}
@@ -667,25 +675,39 @@
void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
{
- if (mInChannelCount > mOutChannelCount) {
- // For case multi to mono, adjust_channels has special logic that will mix first two input
- // channels into a single output channel. In that case, use adjust_channels_non_destructive
- // to keep only one channel data even when contracting to mono.
- adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount,
- mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
- if (mContractedFormat != AUDIO_FORMAT_INVALID
- && mContractedBuffer != nullptr) {
- const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
+ // For case multi to mono, adjust_channels has special logic that will mix first two input
+ // channels into a single output channel. In that case, use adjust_channels_non_destructive
+ // to keep only one channel data even when contracting to mono.
+ adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount,
+ mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
+ if (mContractedFormat != AUDIO_FORMAT_INVALID
+ && mContractedBuffer != nullptr) {
+ const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
+ uint8_t* oriBuf = (uint8_t*) dst + contractedIdx;
+ uint8_t* buf = (uint8_t*) mContractedBuffer
+ + mContractedWrittenFrames * mContractedOutputFrameSize;
+ if (mContractedInChannelCount > mContractedOutChannelCount) {
+ // Adjust the channels first as the contracted buffer may not have enough
+ // space for the data.
+ // Use adjust_channels_non_destructive to avoid mix first two channels into one single
+ // output channel when it is multi to mono.
+ adjust_channels_non_destructive(
+ oriBuf, mContractedInChannelCount, oriBuf, mContractedOutChannelCount,
+ mSampleSizeInBytes, frames * mContractedInChannelCount * mSampleSizeInBytes);
memcpy_by_audio_format(
- (uint8_t*) mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
- mContractedFormat, (uint8_t*) dst + contractedIdx, mFormat,
- mContractedChannelCount * frames);
- mContractedWrittenFrames += frames;
+ buf, mContractedFormat, oriBuf, mFormat, mContractedOutChannelCount * frames);
+ } else {
+ // Copy the data first as the dst buffer may not have enough space for extra channel.
+ memcpy_by_audio_format(
+ buf, mContractedFormat, oriBuf, mFormat, mContractedInChannelCount * frames);
+ // Note that if the contracted data is from MONO to MULTICHANNEL, the first 2 channels
+ // will be duplicated with the original single input channel and all the other channels
+ // will be 0-filled.
+ adjust_channels(
+ buf, mContractedInChannelCount, buf, mContractedOutChannelCount,
+ mContractedSampleSizeInBytes, mContractedInputFrameSize * frames);
}
- } else {
- // Prefer expanding data from the end of each audio frame.
- adjust_channels(src, mInChannelCount, dst, mOutChannelCount,
- mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
+ mContractedWrittenFrames += frames;
}
}