Implement StreamOut::setVolume

Bug: 157158109
Test: boot, check if audio works
Signed-off-by: Roman Kiryanov <rkir@google.com>
Change-Id: I8e40cc7effe590aefbc870b4103c97a648bd3f9a
Merged-In: I8e40cc7effe590aefbc870b4103c97a648bd3f9a
diff --git a/audio/stream_out.cpp b/audio/stream_out.cpp
index 8de1963..f6ae044 100644
--- a/audio/stream_out.cpp
+++ b/audio/stream_out.cpp
@@ -186,6 +186,7 @@
         const size_t availToRead = mDataMQ.availableToRead();
         size_t written = 0;
         if (mDataMQ.read(&mBuffer[0], availToRead)) {
+            applyVolume(&mBuffer[0], availToRead, mStream->getVolumeNumerator());
             status.retval = doWriteImpl(&mBuffer[0], availToRead, written);
 
             mPos.addFrames(pcm_bytes_to_frames(mPcm.get(), written));
@@ -198,6 +199,21 @@
         return status;
     }
 
+    static void applyVolume(void *buf, const size_t szBytes, const int32_t numerator) {
+        constexpr int32_t kDenominator = StreamOut::kVolumeDenominator;
+
+        if (numerator == kDenominator) {
+            return;
+        }
+
+        int16_t *samples = static_cast<int16_t *>(buf);
+        std::for_each(samples,
+                      samples + szBytes / sizeof(*samples),
+                      [numerator](int16_t &x) {
+                          x = (x * numerator + kDenominator / 2) / kDenominator;
+                      });
+    }
+
     IStreamOut::WriteStatus doGetPresentationPosition() {
         IStreamOut::WriteStatus status;
 
@@ -413,9 +429,12 @@
 }
 
 Return<Result> StreamOut::setVolume(float left, float right) {
-    (void)left;
-    (void)right;
-    return Result::NOT_SUPPORTED;
+    if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) {
+        return Result::INVALID_ARGUMENTS;
+    }
+
+    mVolumeNumerator = int16_t((left + right) * kVolumeDenominator / 2);
+    return Result::OK;
 }
 
 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
diff --git a/audio/stream_out.h b/audio/stream_out.h
index c55ad8c..83987ad 100644
--- a/audio/stream_out.h
+++ b/audio/stream_out.h
@@ -15,6 +15,7 @@
  */
 
 #pragma once
+#include <atomic>
 #include <android/hardware/audio/6.0/IStreamOut.h>
 #include <android/hardware/audio/6.0/IDevice.h>
 #include "stream_common.h"
@@ -44,6 +45,8 @@
               const SourceMetadata& sourceMetadata);
     ~StreamOut();
 
+    static constexpr int16_t kVolumeDenominator = 1 << 14;
+
     // IStream
     Return<uint64_t> getFrameSize() override;
     Return<uint64_t> getFrameCount() override;
@@ -101,12 +104,15 @@
     Return<void> getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) override;
     Return<Result> setPlaybackRateParameters(const PlaybackRate &playbackRate) override;
 
+    int16_t getVolumeNumerator() const { return mVolumeNumerator; };
+
 private:
     sp<IDevice> mDev;
     void (* const mUnrefDevice)(IDevice*);
     const StreamCommon mCommon;
     const SourceMetadata mSourceMetadata;
     std::unique_ptr<IOThread> mWriteThread;
+    std::atomic<int16_t> mVolumeNumerator = kVolumeDenominator;
 };
 
 }  // namespace implementation