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

Commit 27e583ba authored by Phil Burk's avatar Phil Burk Committed by Android (Google) Code Review
Browse files

Merge "AudioTrack: add setBufferSizeInFrames()"

parents 33ff89ba c0adecb8
Loading
Loading
Loading
Loading
+24 −2
Original line number Original line Diff line number Diff line
@@ -320,6 +320,25 @@ public:
            uint32_t    channelCount() const { return mChannelCount; }
            uint32_t    channelCount() const { return mChannelCount; }
            size_t      frameCount() const  { return mFrameCount; }
            size_t      frameCount() const  { return mFrameCount; }


    /* Return effective size of audio buffer that an application writes to
     * or a negative error if the track is uninitialized.
     */
            ssize_t     getBufferSizeInFrames();

    /* Set the effective size of audio buffer that an application writes to.
     * This is used to determine the amount of available room in the buffer,
     * which determines when a write will block.
     * This allows an application to raise and lower the audio latency.
     * The requested size may be adjusted so that it is
     * greater or equal to the absolute minimum and
     * less than or equal to the getBufferCapacityInFrames().
     * It may also be adjusted slightly for internal reasons.
     *
     * Return the final size or a negative error if the track is unitialized
     * or does not support variable sizes.
     */
            ssize_t     setBufferSizeInFrames(size_t size);

    /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
    /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
            sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
            sp<IMemory> sharedBuffer() const { return mSharedBuffer; }


@@ -818,8 +837,11 @@ protected:
    mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it
    mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it
    uint32_t                mOriginalSampleRate;
    uint32_t                mOriginalSampleRate;
    AudioPlaybackRate       mPlaybackRate;
    AudioPlaybackRate       mPlaybackRate;
    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is

                                                    // reported back by AudioFlinger to the client
    // Corresponds to current IAudioTrack, value is reported back by AudioFlinger to the client.
    // This allocated buffer size is maintained by the proxy.
    size_t                  mFrameCount;            // maximum size of buffer

    size_t                  mReqFrameCount;         // frame count to request the first or next time
    size_t                  mReqFrameCount;         // frame count to request the first or next time
                                                    // a new IAudioTrack is needed, non-decreasing
                                                    // a new IAudioTrack is needed, non-decreasing


+12 −1
Original line number Original line Diff line number Diff line
@@ -204,6 +204,8 @@ public:
        size_t  mNonContig;             // number of additional non-contiguous frames available
        size_t  mNonContig;             // number of additional non-contiguous frames available
    };
    };


    size_t frameCount() const { return mFrameCount; }

protected:
protected:
    // These refer to shared memory, and are virtual addresses with respect to the current process.
    // These refer to shared memory, and are virtual addresses with respect to the current process.
    // They may have different virtual addresses within the other process.
    // They may have different virtual addresses within the other process.
@@ -305,6 +307,15 @@ public:
        return mEpoch;
        return mEpoch;
    }
    }


    size_t      getBufferSizeInFrames() const { return mBufferSizeInFrames; }
    // See documentation for AudioTrack.setBufferSizeInFrames()
    size_t      setBufferSizeInFrames(size_t requestedSize);

protected:
    // This is set by AudioTrack.setBufferSizeInFrames().
    // A write will not fill the buffer above this limit.
    size_t      mBufferSizeInFrames;      // effective size of the buffer

private:
private:
    Modulo<uint32_t> mEpoch;
    Modulo<uint32_t> mEpoch;
};
};
+25 −0
Original line number Original line Diff line number Diff line
@@ -860,6 +860,31 @@ const AudioPlaybackRate& AudioTrack::getPlaybackRate() const
    return mPlaybackRate;
    return mPlaybackRate;
}
}


ssize_t AudioTrack::getBufferSizeInFrames()
{
    AutoMutex lock(mLock);
    if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
        return NO_INIT;
    }
    return mProxy->getBufferSizeInFrames();
}

ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
{
    AutoMutex lock(mLock);
    if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
        return NO_INIT;
    }
    // Reject if timed track or compressed audio.
    if (mIsTimed || !audio_is_linear_pcm(mFormat)) {
        return INVALID_OPERATION;
    }
    // TODO also need to inform the server side (through mAudioTrack) that
    // the buffer count is reduced, otherwise the track may never start
    // because the server thinks it is never filled.
    return mProxy->setBufferSizeInFrames(bufferSizeInFrames);
}

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()) {
+30 −7
Original line number Original line Diff line number Diff line
@@ -66,7 +66,9 @@ Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t


ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
        size_t frameSize, bool isOut, bool clientInServer)
        size_t frameSize, bool isOut, bool clientInServer)
    : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mEpoch(0)
    : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
    , mBufferSizeInFrames(frameCount)
    , mEpoch(0)
{
{
}
}


@@ -151,6 +153,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques
            rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
            rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
            front = cblk->u.mStreaming.mFront;
            front = cblk->u.mStreaming.mFront;
        }
        }
        // write to rear, read from front
        ssize_t filled = rear - front;
        ssize_t filled = rear - front;
        // pipe should not be overfull
        // pipe should not be overfull
        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
@@ -166,11 +169,17 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques
            cblk->u.mStreaming.mFront = rear;
            cblk->u.mStreaming.mFront = rear;
            (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
            (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
        }
        }
        // don't allow filling pipe beyond the nominal size
        // Don't allow filling pipe beyond the user settable size.
        size_t avail = mIsOut ? mFrameCount - filled : filled;
        // The calculation for avail can go negative if the buffer size
        if (avail > 0) {
        // is suddenly dropped below the amount already in the buffer.
        // So use a signed calculation to prevent a numeric overflow abort.
        ssize_t adjustableSize = (ssize_t) mBufferSizeInFrames;
        ssize_t avail =  (mIsOut) ? adjustableSize - filled : filled;
        if (avail < 0) {
            avail = 0;
        } else if (avail > 0) {
            // 'avail' may be non-contiguous, so return only the first contiguous chunk
            // 'avail' may be non-contiguous, so return only the first contiguous chunk
            size_t part1;
            ssize_t part1;
            if (mIsOut) {
            if (mIsOut) {
                rear &= mFrameCountP2 - 1;
                rear &= mFrameCountP2 - 1;
                part1 = mFrameCountP2 - rear;
                part1 = mFrameCountP2 - rear;
@@ -181,10 +190,10 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques
            if (part1 > avail) {
            if (part1 > avail) {
                part1 = avail;
                part1 = avail;
            }
            }
            if (part1 > buffer->mFrameCount) {
            if (part1 > (ssize_t) buffer->mFrameCount) {
                part1 = buffer->mFrameCount;
                part1 = buffer->mFrameCount;
            }
            }
            buffer->mFrameCount = part1;
            buffer->mFrameCount = (size_t) part1;
            buffer->mRaw = part1 > 0 ?
            buffer->mRaw = part1 > 0 ?
                    &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
                    &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
            buffer->mNonContig = avail - part1;
            buffer->mNonContig = avail - part1;
@@ -347,6 +356,20 @@ size_t ClientProxy::getMisalignment()
            (mFrameCountP2 - 1);
            (mFrameCountP2 - 1);
}
}


size_t ClientProxy::setBufferSizeInFrames(size_t size)
{
    // TODO set minimum to 2X the fast mixer buffer size.
    size_t minimum = 128 * 2; // arbitrary
    size_t maximum = frameCount();
    if (size < minimum) {
        size = minimum;
    } else if (size > maximum) {
        size = maximum;
    }
    mBufferSizeInFrames = size;
    return size;
}

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


void AudioTrackClientProxy::flush()
void AudioTrackClientProxy::flush()