Merge "Add RemixBufferProvider to AudioMixer" into lmp-dev
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index ba135c6..529f2af 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -62,6 +62,10 @@
 #define ALOGVV(a...) do { } while (0)
 #endif
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#endif
+
 // Set kUseNewMixer to true to use the new mixer engine. Otherwise the
 // original code will be used.  This is false for now.
 static const bool kUseNewMixer = false;
@@ -317,6 +321,36 @@
 /*static*/ bool AudioMixer::DownmixerBufferProvider::sIsMultichannelCapable = false;
 /*static*/ effect_descriptor_t AudioMixer::DownmixerBufferProvider::sDwnmFxDesc;
 
+AudioMixer::RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputChannelMask,
+        audio_channel_mask_t outputChannelMask, audio_format_t format,
+        size_t bufferFrameCount) :
+        CopyBufferProvider(
+                audio_bytes_per_sample(format)
+                    * audio_channel_count_from_out_mask(inputChannelMask),
+                audio_bytes_per_sample(format)
+                    * audio_channel_count_from_out_mask(outputChannelMask),
+                bufferFrameCount),
+        mFormat(format),
+        mSampleSize(audio_bytes_per_sample(format)),
+        mInputChannels(audio_channel_count_from_out_mask(inputChannelMask)),
+        mOutputChannels(audio_channel_count_from_out_mask(outputChannelMask))
+{
+    ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %d %d",
+            this, format, inputChannelMask, outputChannelMask,
+            mInputChannels, mOutputChannels);
+    // TODO: consider channel representation in index array formulation
+    // We ignore channel representation, and just use the bits.
+    memcpy_by_index_array_initialization(mIdxAry, ARRAY_SIZE(mIdxAry),
+            audio_channel_mask_get_bits(outputChannelMask),
+            audio_channel_mask_get_bits(inputChannelMask));
+}
+
+void AudioMixer::RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
+{
+    memcpy_by_index_array(dst, mOutputChannels,
+            src, mInputChannels, mIdxAry, mSampleSize, frames);
+}
+
 AudioMixer::ReformatBufferProvider::ReformatBufferProvider(int32_t channels,
         audio_format_t inputFormat, audio_format_t outputFormat,
         size_t bufferFrameCount) :
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 7ad2e75..09a4d89 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -252,8 +252,8 @@
         track_t         tracks[MAX_NUM_TRACKS] __attribute__((aligned(32)));
     };
 
-    // Base AudioBufferProvider class used for ReformatBufferProvider and
-    // DownmixerBufferProvider.
+    // Base AudioBufferProvider class used for DownMixerBufferProvider, RemixBufferProvider,
+    // and ReformatBufferProvider.
     // It handles a private buffer for use in converting format or channel masks from the
     // input data to a form acceptable by the mixer.
     // TODO: Make a ResamplerBufferProvider when integers are entirely removed from the
@@ -326,6 +326,23 @@
         static const int32_t SESSION_ID_INVALID_AND_IGNORED = -2;
     };
 
+    // RemixBufferProvider wraps a track AudioBufferProvider to perform an
+    // upmix or downmix to the proper channel count and mask.
+    class RemixBufferProvider : public CopyBufferProvider {
+    public:
+        RemixBufferProvider(audio_channel_mask_t inputChannelMask,
+                audio_channel_mask_t outputChannelMask, audio_format_t format,
+                size_t bufferFrameCount);
+        virtual void copyFrames(void *dst, const void *src, size_t frames);
+
+    protected:
+        const audio_format_t mFormat;
+        const size_t         mSampleSize;
+        const size_t         mInputChannels;
+        const size_t         mOutputChannels;
+        int8_t               mIdxAry[sizeof(uint32_t)*8]; // 32 bits => channel indices
+    };
+
     // ReformatBufferProvider wraps a track AudioBufferProvider to convert the input data
     // to an acceptable mixer input format type.
     class ReformatBufferProvider : public CopyBufferProvider {