OSDN Git Service

Merge "Camera: Add SECURE camera capability."
authorJayant Chowdhary <jchowdhary@google.com>
Tue, 5 Feb 2019 17:55:02 +0000 (17:55 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 5 Feb 2019 17:55:02 +0000 (17:55 +0000)
audio/include/system/audio.h
audio_utils/Balance.cpp
audio_utils/include/audio_utils/Balance.h

index e61a8ee..16c0b3f 100644 (file)
@@ -100,6 +100,23 @@ static inline audio_attributes_t attributes_initializer(audio_usage_t usage)
     return attributes;
 }
 
+static inline void audio_flags_to_audio_output_flags(
+                                           const audio_flags_mask_t audio_flags,
+                                           audio_output_flags_t *flags)
+{
+    if ((audio_flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
+        *flags = (audio_output_flags_t)(*flags |
+            AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_DIRECT);
+    }
+    if ((audio_flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
+        *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_FAST);
+    }
+    // check deep buffer after flags have been modified above
+    if (*flags == AUDIO_OUTPUT_FLAG_NONE && (audio_flags & AUDIO_FLAG_DEEP_BUFFER) != 0) {
+        *flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+    }
+}
+
 
 /* a unique ID allocated by AudioFlinger for use as an audio_io_handle_t, audio_session_t,
  * effect ID (int), audio_module_handle_t, and audio_patch_handle_t.
index 1fb2031..64769e6 100644 (file)
 
 namespace android::audio_utils {
 
-// Implementation detail: parametric volume curve transfer function
-
-constexpr float CURVE_PARAMETER = 2.f;
-
-static inline float curve(float parameter, float inVolume) {
-    return exp(parameter * inVolume) - 1.f;
-}
-
-Balance::Balance()
-    : mCurveNorm(1.f / curve(CURVE_PARAMETER, 1.f /* inVolume */))
-{
-    setChannelMask(AUDIO_CHANNEL_OUT_STEREO);
-}
-
 void Balance::setChannelMask(audio_channel_mask_t channelMask)
 {
     channelMask &= ~ AUDIO_CHANNEL_HAPTIC_ALL;
@@ -43,10 +29,24 @@ void Balance::setChannelMask(audio_channel_mask_t channelMask)
     mChannelMask = channelMask;
     mChannelCount = audio_channel_count_from_out_mask(channelMask);
 
-    // reset mVolumes (the next process() will recalculate if needed).
+    // save mBalance into balance for later restoring, then reset
+    const float balance = mBalance;
+    mBalance = 0.f;
+
+    // reset mVolumes
     mVolumes.resize(mChannelCount);
     std::fill(mVolumes.begin(), mVolumes.end(), 1.f);
-    mBalance = 0.f;
+
+    // reset ramping variables
+    mRampBalance = 0.f;
+    mRampVolumes.clear();
+
+    if (audio_channel_mask_get_representation(mChannelMask)
+            == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+        mSides.clear();       // mSides unused for channel index masks.
+        setBalance(balance);  // recompute balance
+        return;
+    }
 
     // Implementation detail (may change):
     // For implementation speed, we precompute the side (left, right, center),
@@ -82,18 +82,53 @@ void Balance::setChannelMask(audio_channel_mask_t channelMask)
     mSides.resize(mChannelCount);
     for (unsigned i = 0, channel = channelMask; channel != 0; ++i) {
         const int index = __builtin_ctz(channel);
-        if (index < sizeof(sideFromChannel) / sizeof(sideFromChannel[0])) {
-            mSides[i] = 2; // consider center
-        } else {
+        if (index < std::size(sideFromChannel)) {
             mSides[i] = sideFromChannel[index];
+        } else {
+            mSides[i] = 2; // consider center
         }
         channel &= ~(1 << index);
     }
+    setBalance(balance); // recompute balance
 }
 
-void Balance::process(float *buffer, float balance, size_t frames)
+void Balance::process(float *buffer, size_t frames)
 {
-    setBalance(balance);
+    if (mBalance == 0.f || mChannelCount < 2) {
+        return;
+    }
+
+    if (mRamp) {
+        if (mRampVolumes.size() != mVolumes.size()) {
+            // If mRampVolumes is empty, we do not ramp in this process() but directly
+            // apply the existing mVolumes. We save the balance and volume state here
+            // and fall through to non-ramping code below. The next process() will ramp if needed.
+            mRampBalance = mBalance;
+            mRampVolumes = mVolumes;
+        } else if (mRampBalance != mBalance) {
+            if (frames > 0) {
+                std::vector<float> mDeltas(mVolumes.size());
+                const float r = 1.f / frames;
+                for (size_t j = 0; j < mChannelCount; ++j) {
+                    mDeltas[j] = (mVolumes[j] - mRampVolumes[j]) * r;
+                }
+
+                // ramped balance
+                for (size_t i = 0; i < frames; ++i) {
+                    const float findex = i;
+                    for (size_t j = 0; j < mChannelCount; ++j) { // better precision: delta * i
+                        *buffer++ *= mRampVolumes[j] + mDeltas[j] * findex;
+                    }
+                }
+            }
+            mRampBalance = mBalance;
+            mRampVolumes = mVolumes;
+            return;
+        }
+        // fall through
+    }
+
+    // non-ramped balance
     for (size_t i = 0; i < frames; ++i) {
         for (size_t j = 0; j < mChannelCount; ++j) {
             *buffer++ *= mVolumes[j];
@@ -101,26 +136,22 @@ void Balance::process(float *buffer, float balance, size_t frames)
     }
 }
 
-// Implementation detail (may change):
-// This is not an energy preserving balance (e.g. using sin/cos cross fade or some such).
-// Rather it preserves full gain on left and right when balance is 0.f,
-// and decreases the right or left as one changes the balance.
 void Balance::computeStereoBalance(float balance, float *left, float *right) const
 {
     if (balance > 0.f) {
-        *left = curve(CURVE_PARAMETER, 1.f - balance) * mCurveNorm;
+        *left = mCurve(1.f - balance);
         *right = 1.f;
     } else if (balance < 0.f) {
         *left = 1.f;
-        *right = curve(CURVE_PARAMETER, 1.f + balance) * mCurveNorm;
+        *right = mCurve(1.f + balance);
     } else {
         *left = 1.f;
         *right = 1.f;
     }
 
     // Functionally:
-    // *left = balance > 0.f ? curve(CURVE_PARAMETER, 1.f - balance) * mCurveNorm : 1.f;
-    // *right = balance < 0.f ? curve(CURVE_PARAMETER, 1.f + balance) * mCurveNorm : 1.f;
+    // *left = balance > 0.f ? mCurve(1.f - balance) : 1.f;
+    // *right = balance < 0.f ? mCurve(1.f + balance) : 1.f;
 }
 
 std::string Balance::toString() const
@@ -130,19 +161,25 @@ std::string Balance::toString() const
     for (float volume : mVolumes) {
         ss << " " << volume;
     }
+    // we do not show mSides, which is only valid for channel position masks.
     return ss.str();
 }
 
 void Balance::setBalance(float balance)
 {
-    if (isnan(balance) || fabs(balance) > 1.f              // balance out of range
-            || mBalance == balance || mChannelCount < 2) { // change not applicable
+    if (mBalance == balance                         // no change
+        || isnan(balance) || fabs(balance) > 1.f) { // balance out of range
         return;
     }
 
     mBalance = balance;
 
-    // handle the common cases
+    if (mChannelCount < 2) { // if channel count is 1, mVolumes[0] is already set to 1.f
+        return;              // and if channel count < 2, we don't do anything in process().
+    }
+
+    // Handle the common cases:
+    // stereo and channel index masks only affect the first two channels as left and right.
     if (mChannelMask == AUDIO_CHANNEL_OUT_STEREO
             || audio_channel_mask_get_representation(mChannelMask)
                     == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
@@ -150,6 +187,8 @@ void Balance::setBalance(float balance)
         return;
     }
 
+    // For position masks with more than 2 channels, we consider which side the
+    // speaker position is on to figure the volume used.
     float balanceVolumes[3]; // left, right, center
     computeStereoBalance(balance, &balanceVolumes[0], &balanceVolumes[1]);
     balanceVolumes[2] = 1.f; // center  TODO: consider center scaling.
@@ -160,4 +199,3 @@ void Balance::setBalance(float balance)
 }
 
 } // namespace android::audio_utils
-
index 2a5d444..a1e678d 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef ANDROID_AUDIO_UTILS_BALANCE_H
 #define ANDROID_AUDIO_UTILS_BALANCE_H
 
-#include <math.h>       /* exp */
+#include <math.h>       /* expf */
 #include <sstream>
 #include <system/audio.h>
 #include <vector>
@@ -26,58 +26,151 @@ namespace android::audio_utils {
 
 class Balance {
 public:
-    Balance();
+   /**
+     * \brief Balance processing of left-right volume on audio data.
+     *
+     * Allows processing of audio data with a single balance parameter from [-1, 1].
+     * For efficiency, the class caches balance and channel mask data between calls;
+     * hence, use by multiple threads will require caller locking.
+     *
+     * \param ramp whether to ramp volume or not.
+     * \param curve a monotonic increasing function f: [0, 1] -> [a, b]
+     *        which represents the volume steps from an input domain of [0, 1] to
+     *        an output range [a, b] (ostensibly also from 0 to 1).
+     *        If [a, b] is not [0, 1], it is normalized to [0, 1].
+     *        Curve is typically a convex function, some possible examples:
+     *        [](float x) { return expf(2.f * x); }
+     *        or
+     *        [](float x) { return x * (x + 0.2f); }
+     */
+    explicit Balance(
+            bool ramp = true,
+            std::function<float(float)> curve = [](float x) { return x * (x + 0.2f); })
+        : mRamp(ramp)
+        , mCurve(normalize(std::move(curve))) { }
+
+    /**
+     * \brief Sets whether the process ramps left-right volume changes.
+     *
+     * The default value is true.
+     * The ramp will take place, if needed, on the following process()
+     * using the current balance and volume as the starting point.
+     *
+     * Toggling ramp off and then back on will reset the ramp starting point.
+     *
+     * \param ramp whether ramping is used to smooth volume changes.
+     */
+    void setRamp(bool ramp) {
+        if (ramp == mRamp) return; // no change
+        mRamp = ramp;
+        if (mRamp) { // use current volume and balance as starting point.
+           mRampVolumes = mVolumes;
+           mRampBalance = mBalance;
+        }
+    }
 
     /**
      * \brief Sets the channel mask for data passed in.
      *
-     * \param channelMask The audio output channel mask to use.
+     * setChannelMask() must called before process() to set
+     * a valid output audio channel mask.
+     *
+     * \param channelMask the audio output channel mask to use.
      *                    Invalid channel masks are ignored.
      *
      */
     void setChannelMask(audio_channel_mask_t channelMask);
 
+
+    /**
+     * \brief Sets the left-right balance parameter.
+     *
+     * setBalance() should be called before process() to set
+     * the balance.  The initial value is 0.f (no action).
+     *
+     * \param balance   from -1.f (left) to 0.f (center) to 1.f (right).
+     *
+     */
+    void setBalance(float balance);
+
     /**
      * \brief Processes balance for audio data.
      *
+     * setChannelMask() should be called at least once before calling process()
+     * to set the channel mask.  A balance of 0.f or a channel mask of
+     * less than 2 channels will return with the buffer untouched.
+     *
      * \param buffer    pointer to the audio data to be modified in-place.
-     * \param balance   from -1.f (left) to 0.f (center) to 1.f (right)
-     * \param frames    numer of frames of audio data to convert.
+     * \param frames    number of frames of audio data to convert.
      *
      */
-    void process(float *buffer, float balance, size_t frames);
+    void process(float *buffer, size_t frames);
 
     /**
      * \brief Computes the stereo gains for left and right channels.
      *
-     * \param balance   from -1.f (left) to 0.f (center) to 1.f (right)
+     * Implementation detail (may change):
+     * This is not an energy preserving balance (e.g. using sin/cos cross fade or some such).
+     * Rather balance preserves full gain on left and right when balance is 0.f,
+     * and decreases the right or left as one changes the balance parameter.
+     *
+     * \param balance   from -1.f (left) to 0.f (center) to 1.f (right).
      * \param left      pointer to the float where the left gain will be stored.
      * \param right     pointer to the float where the right gain will be stored.
      */
     void computeStereoBalance(float balance, float *left, float *right) const;
 
     /**
-     * \brief Creates a std::string representation of Balance object for logging,
+     * \brief Creates a std::string representation of Balance object for logging.
+     *
      * \return string representation of Balance object
      */
     std::string toString() const;
 
 private:
 
-    // Called by process() to recompute mVolumes as needed.
-    void setBalance(float balance);
+    /**
+     * \brief Normalizes f: [0, 1] -> [a, b] to g: [0, 1] -> [0, 1].
+     *
+     * A helper function to normalize a float volume function.
+     * g(0) is exactly zero, but g(1) may not necessarily be 1 since we
+     * use reciprocal multiplication instead of division to scale.
+     *
+     * \param f a function from [0, 1] -> [a, b]
+     * \return g a function from [0, 1] -> [0, 1] as a linear function of f.
+     */
+    template<typename T>
+    static std::function<T(T)> normalize(std::function<T(T)> f) {
+        const T f0 = f(0);
+        const T r = T(1) / (f(1) - f0); // reciprocal multiplication
+
+        if (f0 != T(0) ||  // must be exactly 0 at 0, since we promise g(0) == 0
+            fabs(r - T(1)) > std::numeric_limits<T>::epsilon() * 3) { // some fudge allowed on r.
+            return [f, f0, r](T x) { return r * (f(x) - f0); };
+        }
+        // no translation required.
+        return f;
+    }
+
+    // setBalance() changes mBalance and mVolumes based on the channel geometry information.
+    float mBalance = 0.f;              // balance: -1.f (left), 0.f (center), 1.f (right)
+    std::vector<float> mVolumes;       // per channel, the volume adjustment due to balance.
 
-    const float mCurveNorm;            // curve normalization, fixed constant.
+    // setChannelMask() updates mChannelMask, mChannelCount, and mSides to cache the geometry
+    // and then calls setBalance() to update mVolumes.
 
-                                       // process() sets cached mBalance through setBalance().
-    float mBalance = 0.f;              // balance: -1.f (left), 0.f (center), 1.f (right)
+    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_INVALID;
+    size_t mChannelCount = 0;          // from mChannelMask, 0 means no processing done.
 
-    audio_channel_mask_t mChannelMask; // setChannelMask() sets the current channel mask
-    size_t mChannelCount;              // derived from mChannelMask
     std::vector<int> mSides;           // per channel, the side (0 = left, 1 = right, 2 = center)
+                                       // only used for channel position masks.
 
-                                       // process() sets the cached mVolumes
-    std::vector<float> mVolumes;       // per channel, the volume adjustment due to balance.
+    // Ramping variables
+    bool mRamp;                       // whether ramp is enabled.
+    float mRampBalance = 0.f;         // last (starting) balance to begin ramp.
+    std::vector<float> mRampVolumes;  // last (starting) volumes to begin ramp, clear for no ramp.
+
+    const std::function<float(float)> mCurve; // monotone volume transfer func [0, 1] -> [0, 1]
 };
 
 } // namespace android::audio_utils