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

Commit 983f2e02 authored by Ricardo Garcia's avatar Ricardo Garcia Committed by Android (Google) Code Review
Browse files

Merge "Use AudioPlaybackRate to hold TimestretchBufferProvider parameters"

parents d54514d5 5a8a95de
Loading
Loading
Loading
Loading
+74 −4
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@
#define ANDROID_AUDIO_RESAMPLER_PUBLIC_H

#include <stdint.h>
#include <math.h>

namespace android {

// AUDIO_RESAMPLER_DOWN_RATIO_MAX is the maximum ratio between the original
// audio sample rate and the target rate when downsampling,
@@ -34,13 +37,76 @@
// an int32_t of the phase increments, making the resulting sample rate inexact.
#define AUDIO_RESAMPLER_UP_RATIO_MAX 65536

#define AUDIO_TIMESTRETCH_SPEED_MIN    0.5f
#define AUDIO_TIMESTRETCH_SPEED_MAX    2.0f
// AUDIO_TIMESTRETCH_SPEED_MIN and AUDIO_TIMESTRETCH_SPEED_MAX define the min and max time stretch
// speeds supported by the system. These are enforced by the system and values outside this range
// will result in a runtime error.
// Depending on the AudioPlaybackRate::mStretchMode, the effective limits might be narrower than
// the ones specified here
// AUDIO_TIMESTRETCH_SPEED_MIN_DELTA is the minimum absolute speed difference that might trigger a
// parameter update
#define AUDIO_TIMESTRETCH_SPEED_MIN    0.01f
#define AUDIO_TIMESTRETCH_SPEED_MAX    20.0f
#define AUDIO_TIMESTRETCH_SPEED_NORMAL 1.0f
#define AUDIO_TIMESTRETCH_SPEED_MIN_DELTA 0.0001f

#define AUDIO_TIMESTRETCH_PITCH_MIN    0.5f
#define AUDIO_TIMESTRETCH_PITCH_MAX    2.0f
// AUDIO_TIMESTRETCH_PITCH_MIN and AUDIO_TIMESTRETCH_PITCH_MAX define the min and max time stretch
// pitch shifting supported by the system. These are not enforced by the system and values
// outside this range might result in a pitch different than the one requested.
// Depending on the AudioPlaybackRate::mStretchMode, the effective limits might be narrower than
// the ones specified here.
// AUDIO_TIMESTRETCH_PITCH_MIN_DELTA is the minimum absolute pitch difference that might trigger a
// parameter update
#define AUDIO_TIMESTRETCH_PITCH_MIN    0.25f
#define AUDIO_TIMESTRETCH_PITCH_MAX    4.0f
#define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f
#define AUDIO_TIMESTRETCH_PITCH_MIN_DELTA 0.0001f


//Determines the current algorithm used for stretching
enum AudioTimestretchStretchMode : int32_t {
    AUDIO_TIMESTRETCH_STRETCH_DEFAULT            = 0,
    AUDIO_TIMESTRETCH_STRETCH_SPEECH             = 1,
    //TODO: add more stretch modes/algorithms
};

//Limits for AUDIO_TIMESTRETCH_STRETCH_SPEECH mode
#define TIMESTRETCH_SONIC_SPEED_MIN 0.1f
#define TIMESTRETCH_SONIC_SPEED_MAX 6.0f

//Determines behavior of Timestretch if current algorithm can't perform
//with current parameters.
// FALLBACK_CUT_REPEAT: (internal only) for speed <1.0 will truncate frames
//    for speed > 1.0 will repeat frames
// FALLBACK_MUTE: will set all processed frames to zero
// FALLBACK_FAIL:  will stop program execution and log a fatal error
enum AudioTimestretchFallbackMode : int32_t {
    AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT     = -1,
    AUDIO_TIMESTRETCH_FALLBACK_DEFAULT        = 0,
    AUDIO_TIMESTRETCH_FALLBACK_MUTE           = 1,
    AUDIO_TIMESTRETCH_FALLBACK_FAIL           = 2,
};

struct AudioPlaybackRate {
    float mSpeed;
    float mPitch;
    enum AudioTimestretchStretchMode  mStretchMode;
    enum AudioTimestretchFallbackMode mFallbackMode;
};

static const AudioPlaybackRate AUDIO_PLAYBACK_RATE_DEFAULT = {
        AUDIO_TIMESTRETCH_SPEED_NORMAL,
        AUDIO_TIMESTRETCH_PITCH_NORMAL,
        AUDIO_TIMESTRETCH_STRETCH_DEFAULT,
        AUDIO_TIMESTRETCH_FALLBACK_DEFAULT
};

static inline bool isAudioPlaybackRateEqual(const AudioPlaybackRate &pr1,
        const AudioPlaybackRate &pr2) {
    return fabs(pr1.mSpeed - pr2.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
           fabs(pr1.mPitch - pr2.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA &&
           pr2.mStretchMode == pr2.mStretchMode &&
           pr2.mFallbackMode == pr2.mFallbackMode;
}

// TODO: Consider putting these inlines into a class scope

@@ -77,4 +143,8 @@ static inline size_t sourceFramesNeededWithTimestretch(
    return required * (double)speed + 1 + 1; // accounting for rounding dependencies
}

} // namespace android

// ---------------------------------------------------------------------------

#endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H
+4 −4
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <media/AudioResamplerPublic.h>
#include <utils/threads.h>

namespace android {
@@ -369,10 +370,10 @@ public:
     * Speed increases the playback rate of media, but does not alter pitch.
     * Pitch increases the "tonal frequency" of media, but does not affect the playback rate.
     */
            status_t    setPlaybackRate(float speed, float pitch);
            status_t    setPlaybackRate(const AudioPlaybackRate &playbackRate);

    /* Return current playback rate */
            void        getPlaybackRate(float *speed, float *pitch) const;
            const AudioPlaybackRate& getPlaybackRate() const;

    /* Enables looping and sets the start and end points of looping.
     * Only supported for static buffer mode.
@@ -748,8 +749,7 @@ protected:
    float                   mVolume[2];
    float                   mSendLevel;
    mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it
    float                   mSpeed;                 // timestretch: 1.0f for normal speed.
    float                   mPitch;                 // timestretch: 1.0f for normal pitch.
    AudioPlaybackRate       mPlaybackRate;
    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
                                                    // reported back by AudioFlinger to the client
    size_t                  mReqFrameCount;         // frame count to request the first or next time
+8 −18
Original line number Diff line number Diff line
@@ -114,13 +114,7 @@ struct AudioTrackSharedStatic {
                    mPosLoopQueue;
};


struct AudioTrackPlaybackRate {
    float mSpeed;
    float mPitch;
};

typedef SingleStateQueue<AudioTrackPlaybackRate> AudioTrackPlaybackRateQueue;
typedef SingleStateQueue<AudioPlaybackRate> PlaybackRateQueue;

// ----------------------------------------------------------------------------

@@ -168,7 +162,7 @@ private:
                uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
                                            // or 0 == default. Write-only client, read-only server.

                AudioTrackPlaybackRateQueue::Shared mPlaybackRateQueue;
                PlaybackRateQueue::Shared mPlaybackRateQueue;

                // client write-only, server read-only
                uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0
@@ -345,10 +339,7 @@ public:
        mCblk->mSampleRate = sampleRate;
    }

    void        setPlaybackRate(float speed, float pitch) {
        AudioTrackPlaybackRate playbackRate;
        playbackRate.mSpeed = speed;
        playbackRate.mPitch = pitch;
    void        setPlaybackRate(const AudioPlaybackRate& playbackRate) {
        mPlaybackRateMutator.push(playbackRate);
    }

@@ -365,7 +356,7 @@ public:
    status_t    waitStreamEndDone(const struct timespec *requested);

private:
    AudioTrackPlaybackRateQueue::Mutator   mPlaybackRateMutator;
    PlaybackRateQueue::Mutator   mPlaybackRateMutator;
};

class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
@@ -483,8 +474,7 @@ public:
        : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
          mPlaybackRateObserver(&cblk->mPlaybackRateQueue) {
        mCblk->mSampleRate = sampleRate;
        mPlaybackRate.mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL;
        mPlaybackRate.mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL;
        mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
    }
protected:
    virtual ~AudioTrackServerProxy() { }
@@ -520,11 +510,11 @@ public:
    virtual size_t      framesReleased() const { return mCblk->mServer; }

    // Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
    void                getPlaybackRate(float *speed, float *pitch);
    AudioPlaybackRate getPlaybackRate();

private:
    AudioTrackPlaybackRate                  mPlaybackRate;  // last observed playback rate
    AudioTrackPlaybackRateQueue::Observer   mPlaybackRateObserver;
    AudioPlaybackRate             mPlaybackRate;  // last observed playback rate
    PlaybackRateQueue::Observer   mPlaybackRateObserver;
};

class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
+32 −23
Original line number Diff line number Diff line
@@ -393,8 +393,7 @@ status_t AudioTrack::set(
        return BAD_VALUE;
    }
    mSampleRate = sampleRate;
    mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL;
    mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL;
    mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;

    // Make copy of input parameter offloadInfo so that in the future:
    //  (a) createTrack_l doesn't need it as an input parameter
@@ -722,7 +721,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate)
        return NO_INIT;
    }
    // pitch is emulated by adjusting speed and sampleRate
    const uint32_t effectiveSampleRate = adjustSampleRate(rate, mPitch);
    const uint32_t effectiveSampleRate = adjustSampleRate(rate, mPlaybackRate.mPitch);
    if (rate == 0 || effectiveSampleRate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
        return BAD_VALUE;
    }
@@ -757,10 +756,10 @@ uint32_t AudioTrack::getSampleRate() const
    return mSampleRate;
}

status_t AudioTrack::setPlaybackRate(float speed, float pitch)
status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate)
{
    AutoMutex lock(mLock);
    if (speed == mSpeed && pitch == mPitch) {
    if (isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
        return NO_ERROR;
    }
    if (mIsTimed || isOffloadedOrDirect_l()) {
@@ -770,32 +769,37 @@ status_t AudioTrack::setPlaybackRate(float speed, float pitch)
        return INVALID_OPERATION;
    }
    // pitch is emulated by adjusting speed and sampleRate
    const uint32_t effectiveRate = adjustSampleRate(mSampleRate, pitch);
    const float effectiveSpeed = adjustSpeed(speed, pitch);
    const float effectivePitch = adjustPitch(pitch);
    const uint32_t effectiveRate = adjustSampleRate(mSampleRate, playbackRate.mPitch);
    const float effectiveSpeed = adjustSpeed(playbackRate.mSpeed, playbackRate.mPitch);
    const float effectivePitch = adjustPitch(playbackRate.mPitch);
    if (effectiveSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
            || effectiveSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
            || effectivePitch < AUDIO_TIMESTRETCH_PITCH_MIN
            || effectivePitch > AUDIO_TIMESTRETCH_PITCH_MAX) {
        return BAD_VALUE;
        //TODO: add function in AudioResamplerPublic.h to check for validity.
    }
    // Check if the buffer size is compatible.
    if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
        ALOGV("setPlaybackRate(%f, %f) failed", speed, pitch);
        ALOGV("setPlaybackRate(%f, %f) failed", playbackRate.mSpeed, playbackRate.mPitch);
        return BAD_VALUE;
    }
    mSpeed = speed;
    mPitch = pitch;
    mProxy->setPlaybackRate(effectiveSpeed, effectivePitch);
    mPlaybackRate = playbackRate;
    mProxy->setPlaybackRate(playbackRate);

    //modify this
    AudioPlaybackRate playbackRateTemp = playbackRate;
    playbackRateTemp.mSpeed = effectiveSpeed;
    playbackRateTemp.mPitch = effectivePitch;
    mProxy->setPlaybackRate(playbackRateTemp);
    mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate
    return NO_ERROR;
}

void AudioTrack::getPlaybackRate(float *speed, float *pitch) const
const AudioPlaybackRate& AudioTrack::getPlaybackRate() const
{
    AutoMutex lock(mLock);
    *speed = mSpeed;
    *pitch = mPitch;
    return mPlaybackRate;
}

status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
@@ -1169,7 +1173,8 @@ status_t AudioTrack::createTrack_l()
        if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
            // for normal tracks precompute the frame count based on speed.
            const size_t minFrameCount = calculateMinFrameCount(
                    afLatency, afFrameCount, afSampleRate, mSampleRate, mSpeed);
                    afLatency, afFrameCount, afSampleRate, mSampleRate,
                    mPlaybackRate.mSpeed);
            if (frameCount < minFrameCount) {
                frameCount = minFrameCount;
            }
@@ -1341,11 +1346,15 @@ status_t AudioTrack::createTrack_l()
            gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT])));

    mProxy->setSendLevel(mSendLevel);
    const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPitch);
    const float effectiveSpeed = adjustSpeed(mSpeed, mPitch);
    const float effectivePitch = adjustPitch(mPitch);
    const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPlaybackRate.mPitch);
    const float effectiveSpeed = adjustSpeed(mPlaybackRate.mSpeed, mPlaybackRate.mPitch);
    const float effectivePitch = adjustPitch(mPlaybackRate.mPitch);
    mProxy->setSampleRate(effectiveSampleRate);
    mProxy->setPlaybackRate(effectiveSpeed, effectivePitch);

    AudioPlaybackRate playbackRateTemp = mPlaybackRate;
    playbackRateTemp.mSpeed = effectiveSpeed;
    playbackRateTemp.mPitch = effectivePitch;
    mProxy->setPlaybackRate(playbackRateTemp);
    mProxy->setMinimum(mNotificationFramesAct);

    mDeathNotifier = new DeathNotifier(this);
@@ -1715,7 +1724,7 @@ nsecs_t AudioTrack::processAudioBuffer()

    // Cache other fields that will be needed soon
    uint32_t sampleRate = mSampleRate;
    float speed = mSpeed;
    float speed = mPlaybackRate.mSpeed;
    uint32_t notificationFrames = mNotificationFramesAct;
    if (mRefreshRemaining) {
        mRefreshRemaining = false;
@@ -2137,7 +2146,7 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
                }
                const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
                const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
                        / ((double)mSampleRate * mSpeed);
                        / ((double)mSampleRate * mPlaybackRate.mSpeed);

                if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) {
                    // Verify that the counter can't count faster than the sample rate
@@ -2225,7 +2234,7 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
            mChannelCount, mFrameCount);
    result.append(buffer);
    snprintf(buffer, 255, "  sample rate(%u), speed(%f), status(%d)\n",
            mSampleRate, mSpeed, mStatus);
            mSampleRate, mPlaybackRate.mSpeed, mStatus);
    result.append(buffer);
    snprintf(buffer, 255, "  state(%d), latency (%d)\n", mState, mLatency);
    result.append(buffer);
+3 −7
Original line number Diff line number Diff line
@@ -794,14 +794,10 @@ void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
    (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
}

void AudioTrackServerProxy::getPlaybackRate(float *speed, float *pitch)
AudioPlaybackRate AudioTrackServerProxy::getPlaybackRate()
{   // do not call from multiple threads without holding lock
    AudioTrackPlaybackRate playbackRate;
    if (mPlaybackRateObserver.poll(playbackRate)) {
        mPlaybackRate = playbackRate;
    }
    *speed = mPlaybackRate.mSpeed;
    *pitch = mPlaybackRate.mPitch;
    mPlaybackRateObserver.poll(mPlaybackRate);
    return mPlaybackRate;
}

// ---------------------------------------------------------------------------
Loading