Add buffer provider that can adjust channels.

1. Add adjust channels buffer provider, which will expand or contract
sample data from one interleaved channel format to another. Expanded
channels are filled with zeros and put at the end of each frames.
Contracted channels are omitted from the end of each audio frame.

2. Add adjust channels non destructive buffer provider, which could
expand or contract sample data from one interleaved channel format to
another while not destructing the buffer. Extra expanded channels are
interleaved in from the end of the input buffer. Contracted channels are
copied to the end of the output buffer. Contracted channels could be
written to an output buffer with certain audio format.

Test: Manually
Bug: 111454766
Change-Id: I3f963307e73b3f7aa662d4127f78f0c61ac84510
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 2d9e1cb..8b9ee0b 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -19,6 +19,7 @@
 
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
+#include <audio_utils/channels.h>
 #include <external/sonic/sonic.h>
 #include <media/audiohal/EffectBufferHalInterface.h>
 #include <media/audiohal/EffectHalInterface.h>
@@ -609,5 +610,83 @@
         }
     }
 }
+
+AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(audio_format_t format,
+        size_t inChannelCount, size_t outChannelCount, size_t frameCount) :
+        CopyBufferProvider(
+                audio_bytes_per_frame(inChannelCount, format),
+                audio_bytes_per_frame(outChannelCount, format),
+                frameCount),
+        mFormat(format),
+        mInChannelCount(inChannelCount),
+        mOutChannelCount(outChannelCount),
+        mSampleSizeInBytes(audio_bytes_per_sample(format))
+{
+    ALOGV("AdjustBufferProvider(%p)(%#x, %zu, %zu, %zu)",
+            this, format, inChannelCount, outChannelCount, frameCount);
+}
+
+void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
+{
+    adjust_channels(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
+            frames * mInChannelCount * mSampleSizeInBytes);
+}
+
+AdjustChannelsNonDestructiveBufferProvider::AdjustChannelsNonDestructiveBufferProvider(
+        audio_format_t format, size_t inChannelCount, size_t outChannelCount,
+        audio_format_t contractedFormat, size_t contractedFrameCount, void* contractedBuffer) :
+        CopyBufferProvider(
+                audio_bytes_per_frame(inChannelCount, format),
+                audio_bytes_per_frame(outChannelCount, format),
+                0 /*bufferFrameCount*/),
+        mFormat(format),
+        mInChannelCount(inChannelCount),
+        mOutChannelCount(outChannelCount),
+        mSampleSizeInBytes(audio_bytes_per_sample(format)),
+        mContractedChannelCount(inChannelCount - outChannelCount),
+        mContractedFormat(contractedFormat),
+        mContractedFrameCount(contractedFrameCount),
+        mContractedBuffer(contractedBuffer),
+        mContractedWrittenFrames(0)
+{
+    ALOGV("AdjustChannelsNonDestructiveBufferProvider(%p)(%#x, %zu, %zu, %#x, %p)",
+            this, format, inChannelCount, outChannelCount, contractedFormat, contractedBuffer);
+    if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
+        mContractedFrameSize = audio_bytes_per_frame(mContractedChannelCount, mContractedFormat);
+    }
+}
+
+status_t AdjustChannelsNonDestructiveBufferProvider::getNextBuffer(
+        AudioBufferProvider::Buffer* pBuffer)
+{
+    const size_t outFramesLeft = mContractedFrameCount - mContractedWrittenFrames;
+    if (outFramesLeft < pBuffer->frameCount) {
+        // Restrict the frame count so that we don't write over the size of the output buffer.
+        pBuffer->frameCount = outFramesLeft;
+    }
+    return CopyBufferProvider::getNextBuffer(pBuffer);
+}
+
+void AdjustChannelsNonDestructiveBufferProvider::copyFrames(
+        void *dst, const void *src, size_t frames)
+{
+    adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
+            frames * mInChannelCount * mSampleSizeInBytes);
+    if (mContractedFormat != AUDIO_FORMAT_INVALID && mContractedBuffer != NULL
+            && mInChannelCount > mOutChannelCount) {
+        const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
+        memcpy_by_audio_format(
+                (uint8_t*)mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
+                mContractedFormat, (uint8_t*)dst + contractedIdx, mFormat,
+                mContractedChannelCount * frames);
+        mContractedWrittenFrames += frames;
+    }
+}
+
+void AdjustChannelsNonDestructiveBufferProvider::reset()
+{
+    mContractedWrittenFrames = 0;
+    CopyBufferProvider::reset();
+}
 // ----------------------------------------------------------------------------
 } // namespace android