audio hal: Fix multichannel playback

Correctly operate on input and output buffers in DownmixerBufferProvider

Note that playback is a bit choppy, need to investigate further.

Change-Id: I350175dcc9cc7142a1935585a8bd5e9abb1b8eb6
Test: play back a 5.1 file
diff --git a/include/media/BufferProviders.h b/include/media/BufferProviders.h
index d5899ea..9d026f6 100644
--- a/include/media/BufferProviders.h
+++ b/include/media/BufferProviders.h
@@ -113,6 +113,8 @@
 protected:
     sp<EffectsFactoryHalInterface> mEffectsFactory;
     sp<EffectHalInterface> mDownmixInterface;
+    size_t mInFrameSize;
+    size_t mOutFrameSize;
     sp<EffectBufferHalInterface> mInBuffer;
     sp<EffectBufferHalInterface> mOutBuffer;
     effect_config_t    mDownmixConfig;
diff --git a/include/media/audiohal/EffectBufferHalInterface.h b/include/media/audiohal/EffectBufferHalInterface.h
index 102ec56..6fa7940 100644
--- a/include/media/audiohal/EffectBufferHalInterface.h
+++ b/include/media/audiohal/EffectBufferHalInterface.h
@@ -42,6 +42,8 @@
 
     virtual void update() = 0;  // copies data from the external buffer, noop for allocated buffers
     virtual void commit() = 0;  // copies data to the external buffer, noop for allocated buffers
+    virtual void update(size_t size) = 0;  // copies partial data from external buffer
+    virtual void commit(size_t size) = 0;  // copies partial data to external buffer
 
     static status_t allocate(size_t size, sp<EffectBufferHalInterface>* buffer);
     static status_t mirror(void* external, size_t size, sp<EffectBufferHalInterface>* buffer);
diff --git a/media/libaudiohal/EffectBufferHalHidl.cpp b/media/libaudiohal/EffectBufferHalHidl.cpp
index 446d2ef..9a9535b 100644
--- a/media/libaudiohal/EffectBufferHalHidl.cpp
+++ b/media/libaudiohal/EffectBufferHalHidl.cpp
@@ -113,15 +113,25 @@
 }
 
 void EffectBufferHalHidl::update() {
-    if (mExternalData == nullptr) return;
-    mMemory->update();
-    memcpy(mAudioBuffer.raw, mExternalData, mBufferSize);
-    mMemory->commit();
+    update(mBufferSize);
 }
 
 void EffectBufferHalHidl::commit() {
+    commit(mBufferSize);
+}
+
+void EffectBufferHalHidl::update(size_t size) {
     if (mExternalData == nullptr) return;
-    memcpy(mExternalData, mAudioBuffer.raw, mBufferSize);
+    mMemory->update();
+    if (size > mBufferSize) size = mBufferSize;
+    memcpy(mAudioBuffer.raw, mExternalData, size);
+    mMemory->commit();
+}
+
+void EffectBufferHalHidl::commit(size_t size) {
+    if (mExternalData == nullptr) return;
+    if (size > mBufferSize) size = mBufferSize;
+    memcpy(mExternalData, mAudioBuffer.raw, size);
 }
 
 } // namespace android
diff --git a/media/libaudiohal/EffectBufferHalHidl.h b/media/libaudiohal/EffectBufferHalHidl.h
index 4c4ec87..6e9fd0b 100644
--- a/media/libaudiohal/EffectBufferHalHidl.h
+++ b/media/libaudiohal/EffectBufferHalHidl.h
@@ -40,6 +40,8 @@
 
     virtual void update();
     virtual void commit();
+    virtual void update(size_t size);
+    virtual void commit(size_t size);
 
     const AudioBuffer& hidlBuffer() const { return mHidlBuffer; }
 
diff --git a/media/libaudiohal/EffectBufferHalLocal.cpp b/media/libaudiohal/EffectBufferHalLocal.cpp
index 20b1339..7e6ee85 100644
--- a/media/libaudiohal/EffectBufferHalLocal.cpp
+++ b/media/libaudiohal/EffectBufferHalLocal.cpp
@@ -75,4 +75,10 @@
 void EffectBufferHalLocal::commit() {
 }
 
+void EffectBufferHalLocal::update(size_t size) {
+}
+
+void EffectBufferHalLocal::commit(size_t size) {
+}
+
 } // namespace android
diff --git a/media/libaudiohal/EffectBufferHalLocal.h b/media/libaudiohal/EffectBufferHalLocal.h
index df7bd43..202d878 100644
--- a/media/libaudiohal/EffectBufferHalLocal.h
+++ b/media/libaudiohal/EffectBufferHalLocal.h
@@ -35,6 +35,8 @@
 
     virtual void update();
     virtual void commit();
+    virtual void update(size_t size);
+    virtual void commit(size_t size);
 
   private:
     friend class EffectBufferHalInterface;
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 8341a1e..862fef6 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -142,9 +142,9 @@
             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
             bufferFrameCount)  // set bufferFrameCount to 0 to do in-place
 {
-    ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d)",
+    ALOGV("DownmixerBufferProvider(%p)(%#x, %#x, %#x %u %d %d)",
             this, inputChannelMask, outputChannelMask, format,
-            sampleRate, sessionId);
+            sampleRate, sessionId, (int)bufferFrameCount);
     if (!sIsMultichannelCapable) {
         ALOGE("DownmixerBufferProvider() error: not multichannel capable");
         return;
@@ -178,11 +178,13 @@
              EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
      mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
 
+     mInFrameSize =
+             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask);
+     mOutFrameSize =
+             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask);
      status_t status;
      status = EffectBufferHalInterface::mirror(
-             nullptr,
-             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
-             &mInBuffer);
+             nullptr, mInFrameSize * bufferFrameCount, &mInBuffer);
      if (status != 0) {
          ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
          mDownmixInterface.clear();
@@ -190,9 +192,7 @@
          return;
      }
      status = EffectBufferHalInterface::mirror(
-             nullptr,
-             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
-             &mOutBuffer);
+             nullptr, mOutFrameSize * bufferFrameCount, &mOutBuffer);
      if (status != 0) {
          ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
          mInBuffer.clear();
@@ -277,14 +277,18 @@
 {
     mInBuffer->setExternalData(const_cast<void*>(src));
     mInBuffer->setFrameCount(frames);
-    mInBuffer->update();
-    mOutBuffer->setExternalData(dst);
+    mInBuffer->update(mInFrameSize * frames);
     mOutBuffer->setFrameCount(frames);
-    mOutBuffer->update();
+    mOutBuffer->setExternalData(dst);
+    if (dst != src) {
+        // Downmix may be accumulating, need to populate the output buffer
+        // with the dst data.
+        mOutBuffer->update(mOutFrameSize * frames);
+    }
     // may be in-place if src == dst.
     status_t res = mDownmixInterface->process();
     if (res == OK) {
-        mOutBuffer->commit();
+        mOutBuffer->commit(mOutFrameSize * frames);
     } else {
         ALOGE("DownmixBufferProvider error %d", res);
     }