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

Commit 8edb8dc4 authored by Andy Hung's avatar Andy Hung
Browse files

Add playback rate to AudioTrack

Bug: 19196501
Change-Id: I6411e1d3ce652b711a71a6d9df020cb5f60d4714
parent c5656cc9
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,8 @@
#define AUDIO_TIMESTRETCH_PITCH_MAX    2.0f
#define AUDIO_TIMESTRETCH_PITCH_MAX    2.0f
#define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f
#define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f


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

// Returns the source frames needed to resample to destination frames.  This is not a precise
// Returns the source frames needed to resample to destination frames.  This is not a precise
// value and depends on the resampler (and possibly how it handles rounding internally).
// value and depends on the resampler (and possibly how it handles rounding internally).
// Nevertheless, this should be an upper bound on the requirements of the resampler.
// Nevertheless, this should be an upper bound on the requirements of the resampler.
@@ -66,4 +68,13 @@ static inline size_t destinationFramesPossible(size_t srcFrames, uint32_t srcSam
    return dstFrames > 2 ? dstFrames - 2 : 0;
    return dstFrames > 2 ? dstFrames - 2 : 0;
}
}


static inline size_t sourceFramesNeededWithTimestretch(
        uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate,
        float speed) {
    // required is the number of input frames the resampler needs
    size_t required = sourceFramesNeeded(srcSampleRate, dstFramesRequired, dstSampleRate);
    // to deliver this, the time stretcher requires:
    return required * (double)speed + 1 + 1; // accounting for rounding dependencies
}

#endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H
#endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H
+20 −0
Original line number Original line Diff line number Diff line
@@ -359,6 +359,21 @@ public:
    /* Return current source sample rate in Hz */
    /* Return current source sample rate in Hz */
            uint32_t    getSampleRate() const;
            uint32_t    getSampleRate() const;


    /* Set source playback rate for timestretch
     * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
     * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
     *
     * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX
     * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX
     *
     * 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);

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

    /* Enables looping and sets the start and end points of looping.
    /* Enables looping and sets the start and end points of looping.
     * Only supported for static buffer mode.
     * Only supported for static buffer mode.
     *
     *
@@ -719,6 +734,9 @@ protected:
            // increment mPosition by the delta of mServer, and return new value of mPosition
            // increment mPosition by the delta of mServer, and return new value of mPosition
            uint32_t updateAndGetPosition_l();
            uint32_t updateAndGetPosition_l();


            // check sample rate and speed is compatible with AudioTrack
            bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;

    // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
    // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
    sp<IAudioTrack>         mAudioTrack;
    sp<IAudioTrack>         mAudioTrack;
    sp<IMemory>             mCblkMemory;
    sp<IMemory>             mCblkMemory;
@@ -730,6 +748,8 @@ protected:
    float                   mVolume[2];
    float                   mVolume[2];
    float                   mSendLevel;
    float                   mSendLevel;
    mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it
    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.
    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
                                                    // reported back by AudioFlinger to the client
                                                    // reported back by AudioFlinger to the client
    size_t                  mReqFrameCount;         // frame count to request the first or next time
    size_t                  mReqFrameCount;         // frame count to request the first or next time
+34 −2
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
#include <utils/Log.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <utils/RefBase.h>
#include <audio_utils/roundup.h>
#include <audio_utils/roundup.h>
#include <media/AudioResamplerPublic.h>
#include <media/SingleStateQueue.h>
#include <media/SingleStateQueue.h>


namespace android {
namespace android {
@@ -113,6 +114,14 @@ struct AudioTrackSharedStatic {
                    mPosLoopQueue;
                    mPosLoopQueue;
};
};



struct AudioTrackPlaybackRate {
    float mSpeed;
    float mPitch;
};

typedef SingleStateQueue<AudioTrackPlaybackRate> AudioTrackPlaybackRateQueue;

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


// Important: do not add any virtual methods, including ~
// Important: do not add any virtual methods, including ~
@@ -159,6 +168,8 @@ private:
                uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
                uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
                                            // or 0 == default. Write-only client, read-only server.
                                            // or 0 == default. Write-only client, read-only server.


                AudioTrackPlaybackRateQueue::Shared mPlaybackRateQueue;

                // client write-only, server read-only
                // client write-only, server read-only
                uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0
                uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0


@@ -313,7 +324,8 @@ public:
    AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
    AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
            size_t frameSize, bool clientInServer = false)
            size_t frameSize, bool clientInServer = false)
        : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
        : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
          clientInServer) { }
          clientInServer),
          mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { }
    virtual ~AudioTrackClientProxy() { }
    virtual ~AudioTrackClientProxy() { }


    // No barriers on the following operations, so the ordering of loads/stores
    // No barriers on the following operations, so the ordering of loads/stores
@@ -333,6 +345,13 @@ public:
        mCblk->mSampleRate = sampleRate;
        mCblk->mSampleRate = sampleRate;
    }
    }


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

    virtual void flush();
    virtual void flush();


    virtual uint32_t    getUnderrunFrames() const {
    virtual uint32_t    getUnderrunFrames() const {
@@ -344,6 +363,9 @@ public:
    bool        getStreamEndDone() const;
    bool        getStreamEndDone() const;


    status_t    waitStreamEndDone(const struct timespec *requested);
    status_t    waitStreamEndDone(const struct timespec *requested);

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


class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
@@ -458,8 +480,11 @@ class AudioTrackServerProxy : public ServerProxy {
public:
public:
    AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
    AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
            size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
            size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
        : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) {
        : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
          mPlaybackRateObserver(&cblk->mPlaybackRateQueue) {
        mCblk->mSampleRate = sampleRate;
        mCblk->mSampleRate = sampleRate;
        mPlaybackRate.mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL;
        mPlaybackRate.mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL;
    }
    }
protected:
protected:
    virtual ~AudioTrackServerProxy() { }
    virtual ~AudioTrackServerProxy() { }
@@ -493,6 +518,13 @@ public:


    // Return the total number of frames that AudioFlinger has obtained and released
    // Return the total number of frames that AudioFlinger has obtained and released
    virtual size_t      framesReleased() const { return mCblk->mServer; }
    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);

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


class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
+118 −15
Original line number Original line Diff line number Diff line
@@ -56,6 +56,24 @@ static int64_t getNowUs()
    return convertTimespecToUs(tv);
    return convertTimespecToUs(tv);
}
}


// Must match similar computation in createTrack_l in Threads.cpp.
// TODO: Move to a common library
static size_t calculateMinFrameCount(
        uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate,
        uint32_t sampleRate, float speed)
{
    // Ensure that buffer depth covers at least audio hardware latency
    uint32_t minBufCount = afLatencyMs / ((1000 * afFrameCount) / afSampleRate);
    if (minBufCount < 2) {
        minBufCount = 2;
    }
    ALOGV("calculateMinFrameCount afLatency %u  afFrameCount %u  afSampleRate %u  "
            "sampleRate %u  speed %f  minBufCount: %u",
            afLatencyMs, afFrameCount, afSampleRate, sampleRate, speed, minBufCount);
    return minBufCount * sourceFramesNeededWithTimestretch(
            sampleRate, afFrameCount, afSampleRate, speed);
}

// static
// static
status_t AudioTrack::getMinFrameCount(
status_t AudioTrack::getMinFrameCount(
        size_t* frameCount,
        size_t* frameCount,
@@ -94,13 +112,10 @@ status_t AudioTrack::getMinFrameCount(
        return status;
        return status;
    }
    }


    // Ensure that buffer depth covers at least audio hardware latency
    // When called from createTrack, speed is 1.0f (normal speed).
    uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
    // This is rechecked again on setting playback rate (TODO: on setting sample rate, too).
    if (minBufCount < 2) {
    *frameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, 1.0f);
        minBufCount = 2;
    }


    *frameCount = minBufCount * sourceFramesNeeded(sampleRate, afFrameCount, afSampleRate);
    // The formula above should always produce a non-zero value under normal circumstances:
    // The formula above should always produce a non-zero value under normal circumstances:
    // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
    // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
    // Return error in the unlikely event that it does not, as that's part of the API contract.
    // Return error in the unlikely event that it does not, as that's part of the API contract.
@@ -109,8 +124,8 @@ status_t AudioTrack::getMinFrameCount(
                streamType, sampleRate);
                streamType, sampleRate);
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }
    ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%u, afSampleRate=%u, afLatency=%u",
    ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u",
            *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
            *frameCount, afFrameCount, afSampleRate, afLatency);
    return NO_ERROR;
    return NO_ERROR;
}
}


@@ -360,6 +375,8 @@ status_t AudioTrack::set(
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }
    mSampleRate = sampleRate;
    mSampleRate = sampleRate;
    mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL;
    mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL;


    // Make copy of input parameter offloadInfo so that in the future:
    // Make copy of input parameter offloadInfo so that in the future:
    //  (a) createTrack_l doesn't need it as an input parameter
    //  (a) createTrack_l doesn't need it as an input parameter
@@ -689,6 +706,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate)
    if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
    if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }
    // TODO: Should we also check if the buffer size is compatible?


    mSampleRate = rate;
    mSampleRate = rate;
    mProxy->setSampleRate(rate);
    mProxy->setSampleRate(rate);
@@ -719,6 +737,42 @@ uint32_t AudioTrack::getSampleRate() const
    return mSampleRate;
    return mSampleRate;
}
}


status_t AudioTrack::setPlaybackRate(float speed, float pitch)
{
    if (speed < AUDIO_TIMESTRETCH_SPEED_MIN
            || speed > AUDIO_TIMESTRETCH_SPEED_MAX
            || pitch < AUDIO_TIMESTRETCH_PITCH_MIN
            || pitch > AUDIO_TIMESTRETCH_PITCH_MAX) {
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (speed == mSpeed && pitch == mPitch) {
        return NO_ERROR;
    }
    if (mIsTimed || isOffloadedOrDirect_l()) {
        return INVALID_OPERATION;
    }
    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
        return INVALID_OPERATION;
    }
    // Check if the buffer size is compatible.
    if (!isSampleRateSpeedAllowed_l(mSampleRate, speed)) {
        ALOGV("setPlaybackRate(%f, %f) failed", speed, pitch);
        return BAD_VALUE;
    }
    mSpeed = speed;
    mPitch = pitch;
    mProxy->setPlaybackRate(speed, pitch);
    return NO_ERROR;
}

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

status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
{
    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
@@ -1086,8 +1140,16 @@ status_t AudioTrack::createTrack_l()
        // there _is_ a frameCount parameter.  We silently ignore it.
        // there _is_ a frameCount parameter.  We silently ignore it.
        frameCount = mSharedBuffer->size() / mFrameSize;
        frameCount = mSharedBuffer->size() / mFrameSize;
    } else {
    } else {
        // For fast and normal streaming tracks,
        // For fast tracks the frame count calculations and checks are done by server
        // the frame count calculations and checks are done by server

        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);
            if (frameCount < minFrameCount) {
                frameCount = minFrameCount;
            }
        }
    }
    }


    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
@@ -1230,6 +1292,7 @@ status_t AudioTrack::createTrack_l()
    }
    }


    mAudioTrack->attachAuxEffect(mAuxEffectId);
    mAudioTrack->attachAuxEffect(mAuxEffectId);
    // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack)
    // FIXME don't believe this lie
    // FIXME don't believe this lie
    mLatency = afLatency + (1000*frameCount) / mSampleRate;
    mLatency = afLatency + (1000*frameCount) / mSampleRate;


@@ -1255,6 +1318,7 @@ status_t AudioTrack::createTrack_l()


    mProxy->setSendLevel(mSendLevel);
    mProxy->setSendLevel(mSendLevel);
    mProxy->setSampleRate(mSampleRate);
    mProxy->setSampleRate(mSampleRate);
    mProxy->setPlaybackRate(mSpeed, mPitch);
    mProxy->setMinimum(mNotificationFramesAct);
    mProxy->setMinimum(mNotificationFramesAct);


    mDeathNotifier = new DeathNotifier(this);
    mDeathNotifier = new DeathNotifier(this);
@@ -1617,6 +1681,7 @@ nsecs_t AudioTrack::processAudioBuffer()


    // Cache other fields that will be needed soon
    // Cache other fields that will be needed soon
    uint32_t sampleRate = mSampleRate;
    uint32_t sampleRate = mSampleRate;
    float speed = mSpeed;
    uint32_t notificationFrames = mNotificationFramesAct;
    uint32_t notificationFrames = mNotificationFramesAct;
    if (mRefreshRemaining) {
    if (mRefreshRemaining) {
        mRefreshRemaining = false;
        mRefreshRemaining = false;
@@ -1745,7 +1810,7 @@ nsecs_t AudioTrack::processAudioBuffer()
    if (minFrames != (uint32_t) ~0) {
    if (minFrames != (uint32_t) ~0) {
        // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
        // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
        static const nsecs_t kFudgeNs = 10000000LL; // 10 ms
        static const nsecs_t kFudgeNs = 10000000LL; // 10 ms
        ns = ((minFrames * 1000000000LL) / sampleRate) + kFudgeNs;
        ns = ((double)minFrames * 1000000000) / ((double)sampleRate * speed) + kFudgeNs;
    }
    }


    // If not supplying data by EVENT_MORE_DATA, then we're done
    // If not supplying data by EVENT_MORE_DATA, then we're done
@@ -1786,7 +1851,8 @@ nsecs_t AudioTrack::processAudioBuffer()
        if (mRetryOnPartialBuffer && !isOffloaded()) {
        if (mRetryOnPartialBuffer && !isOffloaded()) {
            mRetryOnPartialBuffer = false;
            mRetryOnPartialBuffer = false;
            if (avail < mRemainingFrames) {
            if (avail < mRemainingFrames) {
                int64_t myns = ((mRemainingFrames - avail) * 1100000000LL) / sampleRate;
                int64_t myns = ((double)(mRemainingFrames - avail) * 1100000000)
                        / ((double)sampleRate * speed);
                if (ns < 0 || myns < ns) {
                if (ns < 0 || myns < ns) {
                    ns = myns;
                    ns = myns;
                }
                }
@@ -1841,7 +1907,7 @@ nsecs_t AudioTrack::processAudioBuffer()
        // that total to a sum == notificationFrames.
        // that total to a sum == notificationFrames.
        if (0 < misalignment && misalignment <= mRemainingFrames) {
        if (0 < misalignment && misalignment <= mRemainingFrames) {
            mRemainingFrames = misalignment;
            mRemainingFrames = misalignment;
            return (mRemainingFrames * 1100000000LL) / sampleRate;
            return ((double)mRemainingFrames * 1100000000) / ((double)sampleRate * speed);
        }
        }
#endif
#endif


@@ -1936,6 +2002,41 @@ uint32_t AudioTrack::updateAndGetPosition_l()
    return mPosition += (uint32_t) delta;
    return mPosition += (uint32_t) delta;
}
}


bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
{
    // applicable for mixing tracks only (not offloaded or direct)
    if (mStaticProxy != 0) {
        return true; // static tracks do not have issues with buffer sizing.
    }
    status_t status;
    uint32_t afLatency;
    status = AudioSystem::getLatency(mOutput, &afLatency);
    if (status != NO_ERROR) {
        ALOGE("getLatency(%d) failed status %d", mOutput, status);
        return false;
    }

    size_t afFrameCount;
    status = AudioSystem::getFrameCount(mOutput, &afFrameCount);
    if (status != NO_ERROR) {
        ALOGE("getFrameCount(output=%d) status %d", mOutput, status);
        return false;
    }

    uint32_t afSampleRate;
    status = AudioSystem::getSamplingRate(mOutput, &afSampleRate);
    if (status != NO_ERROR) {
        ALOGE("getSamplingRate(output=%d) status %d", mOutput, status);
        return false;
    }

    const size_t minFrameCount =
            calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, speed);
    ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu  minFrameCount %zu",
            mFrameCount, minFrameCount);
    return mFrameCount >= minFrameCount;
}

status_t AudioTrack::setParameters(const String8& keyValuePairs)
status_t AudioTrack::setParameters(const String8& keyValuePairs)
{
{
    AutoMutex lock(mLock);
    AutoMutex lock(mLock);
@@ -2001,7 +2102,8 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
                    return WOULD_BLOCK;  // stale timestamp time, occurs before start.
                    return WOULD_BLOCK;  // stale timestamp time, occurs before start.
                }
                }
                const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
                const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
                const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate;
                const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
                        / ((double)mSampleRate * mSpeed);


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


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

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


StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
Loading