libaudioprocessing: clamp application provided float audio

For security reason, float buffers provided by application must be
clamped to FLOAT_NOMINAL_RANGE_HEADROOM.
With the new all float pipeline, float are no longer clamped by their
conversion to fixed point.

This patch adds a float buffer provider that clamps float samples
as they are copied to audio pipeline.

Test: Play music, play video in chrome (opensles format float),
      play float pcm audio file specially crafter with >> 1 samples.
Bug: 68099072
Change-Id: I220b436d9982bc43a75715a030efd0e6a0c79fa3
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 93ed5f2..852252d 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -314,6 +314,14 @@
                 targetFormat,
                 kCopyBufferFrameCount));
         requiresReconfigure = true;
+    } else if (mFormat == AUDIO_FORMAT_PCM_FLOAT) {
+        // Input and output are floats, make sure application did not provide > 3db samples
+        // that would break volume application (b/68099072)
+        // TODO: add a trusted source flag to avoid the overhead
+        mReformatBufferProvider.reset(new ClampFloatBufferProvider(
+                audio_channel_count_from_out_mask(channelMask),
+                kCopyBufferFrameCount));
+        requiresReconfigure = true;
     }
     if (targetFormat != mMixerInFormat) {
         mPostDownmixReformatBufferProvider.reset(new ReformatBufferProvider(
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index e19af4a..2d9e1cb 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -376,6 +376,23 @@
     memcpy_by_audio_format(dst, mOutputFormat, src, mInputFormat, frames * mChannelCount);
 }
 
+ClampFloatBufferProvider::ClampFloatBufferProvider(int32_t channelCount, size_t bufferFrameCount) :
+        CopyBufferProvider(
+                channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
+                channelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT),
+                bufferFrameCount),
+        mChannelCount(channelCount)
+{
+    ALOGV("ClampFloatBufferProvider(%p)(%u)", this, channelCount);
+}
+
+void ClampFloatBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
+{
+    memcpy_to_float_from_float_with_clamping((float*)dst, (const float*)src,
+                                             frames * mChannelCount,
+                                             FLOAT_NOMINAL_RANGE_HEADROOM);
+}
+
 TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
         audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
         mChannelCount(channelCount),
diff --git a/media/libmedia/include/media/BufferProviders.h b/media/libmedia/include/media/BufferProviders.h
index 9d026f6..d6a9cfb 100644
--- a/media/libmedia/include/media/BufferProviders.h
+++ b/media/libmedia/include/media/BufferProviders.h
@@ -161,6 +161,17 @@
     const audio_format_t mOutputFormat;
 };
 
+// ClampFloatBufferProvider derives from CopyBufferProvider to clamp floats inside -3db
+class ClampFloatBufferProvider : public CopyBufferProvider {
+public:
+    ClampFloatBufferProvider(int32_t channelCount,
+            size_t bufferFrameCount);
+    virtual void copyFrames(void *dst, const void *src, size_t frames);
+
+protected:
+    const uint32_t       mChannelCount;
+};
+
 // TimestretchBufferProvider derives from PassthruBufferProvider for time stretching
 class TimestretchBufferProvider : public PassthruBufferProvider {
 public: