Add floating and multichannel record to AudioFlinger

Change-Id: Ia388fb012a0b6d81613ef87142a97d76836338f9
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c7d9161..e1ddcbc 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -73,18 +73,18 @@
 class AudioBuffer;
 class AudioResampler;
 class FastMixer;
+class PassthruBufferProvider;
 class ServerProxy;
 
 // ----------------------------------------------------------------------------
 
-// AudioFlinger has a hard-coded upper limit of 2 channels for capture and playback.
-// There is support for > 2 channel tracks down-mixed to 2 channel output via a down-mix effect.
-// Adding full support for > 2 channel capture or playback would require more than simply changing
-// this #define.  There is an independent hard-coded upper limit in AudioMixer;
-// removing that AudioMixer limit would be necessary but insufficient to support > 2 channels.
-// The macro FCC_2 highlights some (but not all) places where there is are 2-channel assumptions.
+// The macro FCC_2 highlights some (but not all) places where there are are 2-channel assumptions.
+// This is typically due to legacy implementation of stereo input or output.
 // Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc.
 #define FCC_2 2     // FCC_2 = Fixed Channel Count 2
+// The macro FCC_8 highlights places where there are 8-channel assumptions.
+// This is typically due to audio mixer and resampler limitations.
+#define FCC_8 8     // FCC_8 = Fixed Channel Count 8
 
 static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
 
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 9e7e8a4..79ac12b 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -105,7 +105,7 @@
             mFormat = mInputSource->format();
             mSampleRate = Format_sampleRate(mFormat);
             unsigned channelCount = Format_channelCount(mFormat);
-            ALOG_ASSERT(channelCount == 1 || channelCount == 2);
+            ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
         }
         dumpState->mSampleRate = mSampleRate;
         eitherChanged = true;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d3d77cd..4039564 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -56,6 +56,7 @@
 
 #include "AudioFlinger.h"
 #include "AudioMixer.h"
+#include "BufferProviders.h"
 #include "FastMixer.h"
 #include "FastCapture.h"
 #include "ServiceUtilities.h"
@@ -94,6 +95,10 @@
     return a < b ? a : b;
 }
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
 namespace android {
 
 // retry counts for buffer fill timeout
@@ -6246,7 +6251,11 @@
             // mDstChannelCount
             // mDstFrameSize
             mBuf(NULL), mBufFrames(0), mBufFrameSize(0),
-            mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0)
+            mResampler(NULL),
+            mIsLegacyDownmix(false),
+            mIsLegacyUpmix(false),
+            mRequiresFloat(false),
+            mInputConverterProvider(NULL)
 {
     (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate,
             dstChannelMask, dstFormat, dstSampleRate);
@@ -6255,13 +6264,18 @@
 AudioFlinger::RecordThread::RecordBufferConverter::~RecordBufferConverter() {
     free(mBuf);
     delete mResampler;
-    free(mRsmpOutBuffer);
+    delete mInputConverterProvider;
 }
 
 size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
         AudioBufferProvider *provider, size_t frames)
 {
-    if (mSrcSampleRate == mDstSampleRate) {
+    if (mInputConverterProvider != NULL) {
+        mInputConverterProvider->setBufferProvider(provider);
+        provider = mInputConverterProvider;
+    }
+
+    if (mResampler == NULL) {
         ALOGVV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
                 mSrcSampleRate, mSrcFormat, mDstFormat);
 
@@ -6273,8 +6287,8 @@
                 frames -= i; // cannot fill request.
                 break;
             }
-            // convert to destination buffer
-            convert(dst, buffer.raw, buffer.frameCount);
+            // format convert to destination buffer
+            convertNoResampler(dst, buffer.raw, buffer.frameCount);
 
             dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize;
             i -= buffer.frameCount;
@@ -6284,20 +6298,17 @@
          ALOGVV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
                  mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat);
 
-        // reallocate mRsmpOutBuffer as needed; we will grow but never shrink
-        if (mRsmpOutFrameCount < frames) {
-            // FIXME why does each track need it's own mRsmpOutBuffer? can't they share?
-            free(mRsmpOutBuffer);
-            // resampler always outputs stereo (FOR NOW)
-            (void)posix_memalign(&mRsmpOutBuffer, 32, frames * FCC_2 * sizeof(int32_t) /*Q4.27*/);
-            mRsmpOutFrameCount = frames;
-        }
+         // reallocate buffer if needed
+         if (mBufFrameSize != 0 && mBufFrames < frames) {
+             free(mBuf);
+             mBufFrames = frames;
+             (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
+         }
         // resampler accumulates, but we only have one source track
-        memset(mRsmpOutBuffer, 0, frames * FCC_2 * sizeof(int32_t));
-        frames = mResampler->resample((int32_t*)mRsmpOutBuffer, frames, provider);
-
-        // convert to destination buffer
-        convert(dst, mRsmpOutBuffer, frames);
+        memset(mBuf, 0, frames * mBufFrameSize);
+        frames = mResampler->resample((int32_t*)mBuf, frames, provider);
+        // format convert to destination buffer
+        convertResampler(dst, mBuf, frames);
     }
     return frames;
 }
@@ -6341,74 +6352,132 @@
     mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
     mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat);
 
-    // do we need a format buffer?
-    if (mSrcFormat != mDstFormat && mDstChannelCount != mSrcChannelCount) {
+    // do we need to resample?
+    delete mResampler;
+    mResampler = NULL;
+    if (mSrcSampleRate != mDstSampleRate) {
+        mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT,
+                mSrcChannelCount, mDstSampleRate);
+        mResampler->setSampleRate(mSrcSampleRate);
+        mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
+    }
+
+    // are we running legacy channel conversion modes?
+    mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO
+                            || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK)
+                   && mDstChannelMask == AUDIO_CHANNEL_IN_MONO;
+    mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO
+                   && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO
+                            || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK);
+
+    // do we need to process in float?
+    mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix;
+
+    // do we need a staging buffer to convert for destination (we can still optimize this)?
+    // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity
+    if (mResampler != NULL) {
+        mBufFrameSize = max(mSrcChannelCount, FCC_2)
+                * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
+    } else if ((mIsLegacyUpmix || mIsLegacyDownmix) && mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
+        mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
+    } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) {
         mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat);
     } else {
         mBufFrameSize = 0;
     }
     mBufFrames = 0; // force the buffer to be resized.
 
-    // do we need to resample?
-    if (mSrcSampleRate != mDstSampleRate) {
-        if (mResampler != NULL) {
-            delete mResampler;
-        }
-        mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_16_BIT,
-                mSrcChannelCount, mDstSampleRate); // may seem confusing...
-        mResampler->setSampleRate(mSrcSampleRate);
-        mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
+    // do we need an input converter buffer provider to give us float?
+    delete mInputConverterProvider;
+    mInputConverterProvider = NULL;
+    if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) {
+        mInputConverterProvider = new ReformatBufferProvider(
+                audio_channel_count_from_in_mask(mSrcChannelMask),
+                mSrcFormat,
+                AUDIO_FORMAT_PCM_FLOAT,
+                256 /* provider buffer frame count */);
+    }
+
+    // do we need a remixer to do channel mask conversion
+    if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) {
+        (void) memcpy_by_index_array_initialization_from_channel_mask(
+                mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask);
     }
     return NO_ERROR;
 }
 
-void AudioFlinger::RecordThread::RecordBufferConverter::convert(
-        void *dst, /*const*/ void *src, size_t frames)
+void AudioFlinger::RecordThread::RecordBufferConverter::convertNoResampler(
+        void *dst, const void *src, size_t frames)
 {
-    // check if a memcpy will do
-    if (mResampler == NULL
-            && mSrcChannelCount == mDstChannelCount
-            && mSrcFormat == mDstFormat) {
-        memcpy(dst, src,
-                frames * mDstChannelCount * audio_bytes_per_sample(mDstFormat));
-        return;
-    }
-    // reallocate buffer if needed
+    // src is native type unless there is legacy upmix or downmix, whereupon it is float.
     if (mBufFrameSize != 0 && mBufFrames < frames) {
         free(mBuf);
         mBufFrames = frames;
         (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
     }
-    // do processing
-    if (mResampler != NULL) {
-        // src channel count is always >= 2.
+    // do we need to do legacy upmix and downmix?
+    if (mIsLegacyUpmix || mIsLegacyDownmix) {
         void *dstBuf = mBuf != NULL ? mBuf : dst;
-        // ditherAndClamp() works as long as all buffers returned by
-        // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
-        if (mDstChannelCount == 1) {
-            // the resampler always outputs stereo samples.
-            // FIXME: this rewrites back into src
-            ditherAndClamp((int32_t *)src, (const int32_t *)src, frames);
-            downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf,
-                    (const int16_t *)src, frames);
-        } else {
-            ditherAndClamp((int32_t *)dstBuf, (const int32_t *)src, frames);
+        if (mIsLegacyUpmix) {
+            upmix_to_stereo_float_from_mono_float((float *)dstBuf,
+                    (const float *)src, frames);
+        } else /*mIsLegacyDownmix */ {
+            downmix_to_mono_float_from_stereo_float((float *)dstBuf,
+                    (const float *)src, frames);
         }
-    } else if (mSrcChannelCount != mDstChannelCount) {
+        if (mBuf != NULL) {
+            memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT,
+                    frames * mDstChannelCount);
+        }
+        return;
+    }
+    // do we need to do channel mask conversion?
+    if (mSrcChannelMask != mDstChannelMask) {
         void *dstBuf = mBuf != NULL ? mBuf : dst;
+        memcpy_by_index_array(dstBuf, mDstChannelCount,
+                src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames);
+        if (dstBuf == dst) {
+            return; // format is the same
+        }
+    }
+    // convert to destination buffer
+    const void *convertBuf = mBuf != NULL ? mBuf : src;
+    memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat,
+            frames * mDstChannelCount);
+}
+
+void AudioFlinger::RecordThread::RecordBufferConverter::convertResampler(
+        void *dst, /*not-a-const*/ void *src, size_t frames)
+{
+    // src buffer format is ALWAYS float when entering this routine
+    if (mIsLegacyUpmix) {
+        ; // mono to stereo already handled by resampler
+    } else if (mIsLegacyDownmix
+            || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) {
+        // the resampler outputs stereo for mono input channel (a feature?)
+        // must convert to mono
+        downmix_to_mono_float_from_stereo_float((float *)src,
+                (const float *)src, frames);
+    } else if (mSrcChannelMask != mDstChannelMask) {
+        // convert to mono channel again for channel mask conversion (could be skipped
+        // with further optimization).
         if (mSrcChannelCount == 1) {
-            upmix_to_stereo_i16_from_mono_i16((int16_t *)dstBuf, (const int16_t *)src,
-                    frames);
-        } else {
-            downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf,
-                    (const int16_t *)src, frames);
+            downmix_to_mono_float_from_stereo_float((float *)src,
+                (const float *)src, frames);
         }
+        // convert to destination format (in place, OK as float is larger than other types)
+        if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
+            memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
+                    frames * mSrcChannelCount);
+        }
+        // channel convert and save to dst
+        memcpy_by_index_array(dst, mDstChannelCount,
+                src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames);
+        return;
     }
-    if (mSrcFormat != mDstFormat) {
-        void *srcBuf = mBuf != NULL ? mBuf : src;
-        memcpy_by_audio_format(dst, mDstFormat, srcBuf, mSrcFormat,
-                frames * mDstChannelCount);
-    }
+    // convert to destination format and save to dst
+    memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
+            frames * mDstChannelCount);
 }
 
 bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
@@ -6421,6 +6490,10 @@
     audio_format_t reqFormat = mFormat;
     uint32_t samplingRate = mSampleRate;
     audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
+    // possible that we are > 2 channels, use channel index mask
+    if (channelMask == AUDIO_CHANNEL_INVALID && mChannelCount <= FCC_8) {
+        audio_channel_mask_for_index_assignment_from_count(mChannelCount);
+    }
 
     AudioParameter param = AudioParameter(keyValuePair);
     int value;
@@ -6441,7 +6514,8 @@
     }
     if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
         audio_channel_mask_t mask = (audio_channel_mask_t) value;
-        if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
+        if (!audio_is_input_channel(mask) ||
+                audio_channel_count_from_in_mask(mask) > FCC_8) {
             status = BAD_VALUE;
         } else {
             channelMask = mask;
@@ -6566,10 +6640,13 @@
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
     mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
     mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
+    if (mChannelCount > FCC_8) {
+        ALOGE("HAL channel count %d > %d", mChannelCount, FCC_8);
+    }
     mHALFormat = mInput->stream->common.get_format(&mInput->stream->common);
     mFormat = mHALFormat;
-    if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
-        ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
+    if (!audio_is_linear_pcm(mFormat)) {
+        ALOGE("HAL format %#x is not linear pcm", mFormat);
     }
     mFrameSize = audio_stream_in_frame_size(mInput->stream);
     mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ed2e4a1..b7c1ed1 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1130,8 +1130,11 @@
         }
 
     private:
-        // internal convert function for format and channel mask.
-        void convert(void *dst, /*const*/ void *src, size_t frames);
+        // format conversion when not using resampler
+        void convertNoResampler(void *dst, const void *src, size_t frames);
+
+        // format conversion when using resampler; modifies src in-place
+        void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames);
 
         // user provided information
         audio_channel_mask_t mSrcChannelMask;
@@ -1153,10 +1156,12 @@
 
         // resampler info
         AudioResampler      *mResampler;
-        // interleaved stereo pairs of fixed-point Q4.27 or float depending on resampler
-        void                *mRsmpOutBuffer;
-        // current allocated frame count for the above, which may be larger than needed
-        size_t               mRsmpOutFrameCount;
+
+        bool                 mIsLegacyDownmix;  // legacy stereo to mono conversion needed
+        bool                 mIsLegacyUpmix;    // legacy mono to stereo conversion needed
+        bool                 mRequiresFloat;    // data processing requires float (e.g. resampler)
+        PassthruBufferProvider *mInputConverterProvider;    // converts input to float
+        int8_t               mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion
     };
 
 #include "RecordTracks.h"