Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 469826c6 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Use modulo position variables in AudioTrack and AudioRecord"

parents ee25a737 90e8a97d
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
#include <media/IAudioRecord.h>
#include <media/Modulo.h>
#include <utils/threads.h>

namespace android {
@@ -526,7 +527,7 @@ private:

            // caller must hold lock on mLock for all _l methods

            status_t openRecord_l(size_t epoch, const String16& opPackageName);
            status_t openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);

            // FIXME enum is faster than strcmp() for parameter 'from'
            status_t restoreRecord_l(const char *from);
@@ -556,9 +557,9 @@ private:
    bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
    uint32_t                mObservedSequence;      // last observed value of mSequence

    uint32_t                mMarkerPosition;        // in wrapping (overflow) frame units
    Modulo<uint32_t>        mMarkerPosition;        // in wrapping (overflow) frame units
    bool                    mMarkerReached;
    uint32_t                mNewPosition;           // in frames
    Modulo<uint32_t>        mNewPosition;           // in frames
    uint32_t                mUpdatePeriod;          // in frames, zero means no EVENT_NEW_POS

    status_t                mStatus;
+7 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <media/AudioResamplerPublic.h>
#include <media/Modulo.h>
#include <utils/threads.h>

namespace android {
@@ -798,7 +799,7 @@ protected:
                { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }

            // increment mPosition by the delta of mServer, and return new value of mPosition
            uint32_t updateAndGetPosition_l();
            Modulo<uint32_t> updateAndGetPosition_l();

            // check sample rate and speed is compatible with AudioTrack
            bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;
@@ -885,19 +886,19 @@ protected:
    bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
    uint32_t                mObservedSequence;      // last observed value of mSequence

    uint32_t                mMarkerPosition;        // in wrapping (overflow) frame units
    Modulo<uint32_t>        mMarkerPosition;        // in wrapping (overflow) frame units
    bool                    mMarkerReached;
    uint32_t                mNewPosition;           // in frames
    Modulo<uint32_t>        mNewPosition;           // in frames
    uint32_t                mUpdatePeriod;          // in frames, zero means no EVENT_NEW_POS

    uint32_t                mServer;                // in frames, last known mProxy->getPosition()
    Modulo<uint32_t>        mServer;                // in frames, last known mProxy->getPosition()
                                                    // which is count of frames consumed by server,
                                                    // reset by new IAudioTrack,
                                                    // whether it is reset by stop() is TBD
    uint32_t                mPosition;              // in frames, like mServer except continues
    Modulo<uint32_t>        mPosition;              // in frames, like mServer except continues
                                                    // monotonically after new IAudioTrack,
                                                    // and could be easily widened to uint64_t
    uint32_t                mReleased;              // in frames, count of frames released to server
    Modulo<uint32_t>        mReleased;              // count of frames released to server
                                                    // but not necessarily consumed by server,
                                                    // reset by stop() but continues monotonically
                                                    // after new IAudioTrack to restore mPosition,

include/media/Modulo.h

0 → 100644
+220 −0
Original line number Diff line number Diff line
/*
 * Copyright 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_MODULO_H
#define ANDROID_MODULO_H

namespace android {

// Modulo class is used for intentionally wrapping variables such as
// counters and timers.
//
// It may also be used for variables whose computation depends on the
// associativity of addition or subtraction.
//
// Features:
// 1) Modulo checks type sizes before performing operations to ensure
//    that the wrap points match. This is critical for safe modular arithmetic.
// 2) Modulo returns Modulo types from arithmetic operations, thereby
//    avoiding unintentional use in a non-modular computation.  A Modulo
//    type is converted to its base non-Modulo type through the value() function.
// 3) Modulo separates out overflowable types from non-overflowable types.
//    A signed overflow is technically undefined in C and C++.
//    Modulo types do not participate in sanitization.
// 4) Modulo comparisons are based on signed differences to account for wrap;
//    this is not the same as the direct comparison of values.
// 5) Safe use of binary arithmetic operations relies on conversions of
//    signed operands to unsigned operands (which are modular arithmetic safe).
//    Conversions which are implementation-defined are assumed to use 2's complement
//    representation. (See A, B, C, D from the ISO/IEC FDIS 14882
//    Information technology — Programming languages — C++).
//
// A: ISO/IEC 14882:2011(E) p84 section 4.7 Integral conversions
// (2) If the destination type is unsigned, the resulting value is the least unsigned
// integer congruent to the source integer (modulo 2^n where n is the number of bits
// used to represent the unsigned type). [ Note: In a two’s complement representation,
// this conversion is conceptual and there is no change in the bit pattern (if there
// is no truncation). — end note ]
// (3) If the destination type is signed, the value is unchanged if it can be represented
// in the destination type (and bit-field width); otherwise, the value is
// implementation-defined.
//
// B: ISO/IEC 14882:2011(E) p88 section 5 Expressions
// (9) Many binary operators that expect operands of arithmetic or enumeration type
// cause conversions and yield result types in a similar way. The purpose is to
// yield a common type, which is also the type of the result. This pattern is called
// the usual arithmetic conversions, which are defined as follows:
// [...]
// Otherwise, if both operands have signed integer types or both have unsigned
// integer types, the operand with the type of lesser integer conversion rank shall be
// converted to the type of the operand with greater rank.
// — Otherwise, if the operand that has unsigned integer type has rank greater than
// or equal to the rank of the type of the other operand, the operand with signed
// integer type shall be converted to the type of the operand with unsigned integer type.
//
// C: ISO/IEC 14882:2011(E) p86 section 4.13 Integer conversion rank
// [...] The rank of long long int shall be greater than the rank of long int,
// which shall be greater than the rank of int, which shall be greater than the
// rank of short int, which shall be greater than the rank of signed char.
// — The rank of any unsigned integer type shall equal the rank of the corresponding
// signed integer type.
//
// D: ISO/IEC 14882:2011(E) p75 section 3.9.1 Fundamental types
// [...] Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo
// 2^n where n is the number of bits in the value representation of that particular
// size of integer.
//
// Note:
// Other libraries do exist for safe integer operations which can detect the
// possibility of overflow (SafeInt from MS and safe-iop in android).
// Signed safe computation is also possible from the art header safe_math.h.

template <typename T> class Modulo {
    T mValue;

public:
    typedef typename std::make_signed<T>::type signedT;
    typedef typename std::make_unsigned<T>::type unsignedT;

    Modulo() { } // intentionally uninitialized data
    Modulo(const T &value) { mValue = value; }
    const T & value() const { return mValue; } // not assignable
    signedT signedValue() const { return mValue; }
    unsignedT unsignedValue() const { return mValue; }
    void getValue(T *value) const { *value = mValue; } // more type safe than value()

    // modular operations valid only if size of T <= size of S.
    template <typename S>
    __attribute__((no_sanitize("integer")))
    Modulo<T> operator +=(const Modulo<S> &other) {
        static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
        mValue += other.unsignedValue();
        return *this;
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    Modulo<T> operator -=(const Modulo<S> &other) {
        static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
        mValue -= other.unsignedValue();
        return *this;
    }

    // modular operations resulting in a value valid only at the smaller of the two
    // Modulo base type sizes, but we only allow equal sizes to avoid confusion.
    template <typename S>
    __attribute__((no_sanitize("integer")))
    const Modulo<T> operator +(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return Modulo<T>(mValue + other.unsignedValue());
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    const Modulo<T> operator -(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return Modulo<T>(mValue - other.unsignedValue());
    }

    // modular operations that should be checked only at the smaller of
    // the two type sizes, but we only allow equal sizes to avoid confusion.
    //
    // Caution: These relational and comparison operations are not equivalent to
    // the base type operations.
    template <typename S>
    __attribute__((no_sanitize("integer")))
    bool operator >(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return static_cast<signedT>(mValue - other.unsignedValue()) > 0;
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    bool operator >=(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return static_cast<signedT>(mValue - other.unsignedValue()) >= 0;
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    bool operator ==(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return static_cast<signedT>(mValue - other.unsignedValue()) == 0;
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    bool operator <=(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return static_cast<signedT>(mValue - other.unsignedValue()) <= 0;
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    bool operator <(const Modulo<S> &other) const {
        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
        return static_cast<signedT>(mValue - other.unsignedValue()) < 0;
    }


    // modular operations with a non-Modulo type allowed with wrapping
    // because there should be no confusion as to the meaning.
    template <typename S>
    __attribute__((no_sanitize("integer")))
    Modulo<T> operator +=(const S &other) {
        mValue += unsignedT(other);
        return *this;
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    Modulo<T> operator -=(const S &other) {
        mValue -= unsignedT(other);
        return *this;
    }

    // modular operations with a non-Modulo type allowed with wrapping,
    // but we restrict this only when size of T is greater than or equal to
    // the size of S to avoid confusion with the nature of overflow.
    //
    // Use of this follows left-associative style.
    //
    // Note: a Modulo type may be promoted by using "differences" off of
    // a larger sized type, but we do not automate this.
    template <typename S>
    __attribute__((no_sanitize("integer")))
    const Modulo<T> operator +(const S &other) const {
        static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
        return Modulo<T>(mValue + unsignedT(other));
    }

    template <typename S>
    __attribute__((no_sanitize("integer")))
    const Modulo<T> operator -(const S &other) const {
        static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
        return Modulo<T>(mValue - unsignedT(other));
    }

    // multiply is intentionally omitted, but it is a common operator in
    // modular arithmetic.

    // shift operations are intentionally omitted, but perhaps useful.
    // For example, left-shifting a negative number is undefined in C++11.
};

} // namespace android

#endif /* ANDROID_MODULO_H */
+5 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <utils/RefBase.h>
#include <audio_utils/roundup.h>
#include <media/AudioResamplerPublic.h>
#include <media/Modulo.h>
#include <media/SingleStateQueue.h>

namespace android {
@@ -280,11 +281,11 @@ public:
    // Call to force an obtainBuffer() to return quickly with -EINTR
    void        interrupt();

    size_t      getPosition() {
    Modulo<uint32_t> getPosition() {
        return mEpoch + mCblk->mServer;
    }

    void        setEpoch(size_t epoch) {
    void             setEpoch(const Modulo<uint32_t> &epoch) {
        mEpoch = epoch;
    }

@@ -300,14 +301,14 @@ public:
    // in order for the client to be aligned at start of buffer
    virtual size_t  getMisalignment();

    size_t      getEpoch() const {
    Modulo<uint32_t> getEpoch() const {
        return mEpoch;
    }

    size_t      getFramesFilled();

private:
    size_t      mEpoch;
    Modulo<uint32_t> mEpoch;
};

// ----------------------------------------------------------------------------
+12 −12
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
    }

    AutoMutex lock(mLock);
    *marker = mMarkerPosition;
    mMarkerPosition.getValue(marker);

    return NO_ERROR;
}
@@ -438,7 +438,7 @@ status_t AudioRecord::getPosition(uint32_t *position) const
    }

    AutoMutex lock(mLock);
    *position = mProxy->getPosition();
    mProxy->getPosition().getValue(position);

    return NO_ERROR;
}
@@ -480,7 +480,7 @@ audio_port_handle_t AudioRecord::getRoutedDeviceId() {
// -------------------------------------------------------------------------

// must be called with mLock held
status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName)
status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
{
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
    if (audioFlinger == 0) {
@@ -890,23 +890,23 @@ nsecs_t AudioRecord::processAudioBuffer()
    }

    // Get current position of server
    size_t position = mProxy->getPosition();
    Modulo<uint32_t> position(mProxy->getPosition());

    // Manage marker callback
    bool markerReached = false;
    size_t markerPosition = mMarkerPosition;
    Modulo<uint32_t> markerPosition(mMarkerPosition);
    // FIXME fails for wraparound, need 64 bits
    if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
    if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
        mMarkerReached = markerReached = true;
    }

    // Determine the number of new position callback(s) that will be needed, while locked
    size_t newPosCount = 0;
    size_t newPosition = mNewPosition;
    Modulo<uint32_t> newPosition(mNewPosition);
    uint32_t updatePeriod = mUpdatePeriod;
    // FIXME fails for wraparound, need 64 bits
    if (updatePeriod > 0 && position >= newPosition) {
        newPosCount = ((position - newPosition) / updatePeriod) + 1;
        newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
        mNewPosition += updatePeriod * newPosCount;
    }

@@ -933,7 +933,7 @@ nsecs_t AudioRecord::processAudioBuffer()
        mCbf(EVENT_MARKER, mUserData, &markerPosition);
    }
    while (newPosCount > 0) {
        size_t temp = newPosition;
        size_t temp = newPosition.value(); // FIXME size_t != uint32_t
        mCbf(EVENT_NEW_POS, mUserData, &temp);
        newPosition += updatePeriod;
        newPosCount--;
@@ -951,10 +951,10 @@ nsecs_t AudioRecord::processAudioBuffer()
    // Compute the estimated time until the next timed event (position, markers)
    uint32_t minFrames = ~0;
    if (!markerReached && position < markerPosition) {
        minFrames = markerPosition - position;
        minFrames = (markerPosition - position).value();
    }
    if (updatePeriod > 0) {
        uint32_t remaining = newPosition - position;
        uint32_t remaining = (newPosition - position).value();
        if (remaining < minFrames) {
            minFrames = remaining;
        }
@@ -1087,7 +1087,7 @@ status_t AudioRecord::restoreRecord_l(const char *from)
    // if the new IAudioRecord is created, openRecord_l() will modify the
    // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
    // It will also delete the strong references on previous IAudioRecord and IMemory
    size_t position = mProxy->getPosition();
    Modulo<uint32_t> position(mProxy->getPosition());
    mNewPosition = position + mUpdatePeriod;
    status_t result = openRecord_l(position, mOpPackageName);
    if (result == NO_ERROR) {
Loading