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

Commit 90eea763 authored by Phil Burk's avatar Phil Burk
Browse files

AudioFlinger: reset frame position on standby



The HAL does not reset the frame position on standby().
But applications expect the frame position to be reset.
So we subtract the position at standby from the current position.

Bug: 21724210
Bug: 21930805
Change-Id: I0c4520ba1c6c06a580f45f6bafc8cf1d56969f07
Signed-off-by: default avatarPhil Burk <philburk@google.com>
parent 29b7cec9
Loading
Loading
Loading
Loading
+75 −10
Original line number Diff line number Diff line
@@ -27,11 +27,16 @@
namespace android {

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

AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
        : audioHwDev(dev)
        , stream(NULL)
        , flags(flags)
        , mFramesWritten(0)
        , mFramesWrittenAtStandby(0)
        , mRenderPosition(0)
        , mRateMultiplier(1)
        , mHalFormatIsLinearPcm(false)
        , mHalFrameSize(0)
{
}

@@ -40,12 +45,41 @@ audio_hw_device_t* AudioStreamOut::hwDev() const
    return audioHwDev->hwDevice();
}

status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
status_t AudioStreamOut::getRenderPosition(uint64_t *frames)
{
    if (stream == NULL) {
        return NO_INIT;
    }
    return stream->get_render_position(stream, frames);

    uint32_t halPosition = 0;
    status_t status = stream->get_render_position(stream, &halPosition);
    if (status != NO_ERROR) {
        return status;
    }

    // Maintain a 64-bit render position using the 32-bit result from the HAL.
    // This delta calculation relies on the arithmetic overflow behavior
    // of integers. For example (100 - 0xFFFFFFF0) = 116.
    uint32_t truncatedPosition = (uint32_t)mRenderPosition;
    int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition);
    if (deltaHalPosition > 0) {
        mRenderPosition += deltaHalPosition;
    }
    // Scale from HAL sample rate to application rate.
    *frames = mRenderPosition / mRateMultiplier;

    return status;
}

// return bottom 32-bits of the render position
status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
{
    uint64_t position64 = 0;
    status_t status = getRenderPosition(&position64);
    if (status == NO_ERROR) {
        *frames = (uint32_t)position64;
    }
    return status;
}

status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp)
@@ -53,7 +87,26 @@ status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timesp
    if (stream == NULL) {
        return NO_INIT;
    }
    return stream->get_presentation_position(stream, frames, timestamp);

    uint64_t halPosition = 0;
    status_t status = stream->get_presentation_position(stream, &halPosition, timestamp);
    if (status != NO_ERROR) {
        return status;
    }

    // Adjust for standby using HAL rate frames.
    // Only apply this correction if the HAL is getting PCM frames.
    if (mHalFormatIsLinearPcm) {
        uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
                0 : (halPosition - mFramesWrittenAtStandby);
        // Scale from HAL sample rate to application rate.
        *frames = adjustedPosition / mRateMultiplier;
    } else {
        // For offloaded MP3 and other compressed formats.
        *frames = halPosition;
    }

    return status;
}

status_t AudioStreamOut::open(
@@ -82,6 +135,9 @@ status_t AudioStreamOut::open(

    if (status == NO_ERROR) {
        stream = outStream;
        mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
        ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
        mHalFrameSize = audio_stream_out_frame_size(stream);
    }

    return status;
@@ -89,13 +145,15 @@ status_t AudioStreamOut::open(

size_t AudioStreamOut::getFrameSize()
{
    ALOG_ASSERT(stream != NULL);
    return audio_stream_out_frame_size(stream);
    return mHalFrameSize;
}

int AudioStreamOut::flush()
{
    ALOG_ASSERT(stream != NULL);
    mRenderPosition = 0;
    mFramesWritten = 0;
    mFramesWrittenAtStandby = 0;
    if (stream->flush != NULL) {
        return stream->flush(stream);
    }
@@ -105,13 +163,20 @@ int AudioStreamOut::flush()
int AudioStreamOut::standby()
{
    ALOG_ASSERT(stream != NULL);
    mRenderPosition = 0;
    mFramesWrittenAtStandby = mFramesWritten;
    ALOGI("AudioStreamOut::standby(), mFramesWrittenAtStandby = %llu", mFramesWrittenAtStandby);
    return stream->common.standby(&stream->common);
}

ssize_t AudioStreamOut::write(const void* buffer, size_t bytes)
ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes)
{
    ALOG_ASSERT(stream != NULL);
    return stream->write(stream, buffer, bytes);
    ssize_t bytesWritten = stream->write(stream, buffer, numBytes);
    if (bytesWritten > 0 && mHalFrameSize > 0) {
        mFramesWritten += bytesWritten / mHalFrameSize;
    }
    return bytesWritten;
}

} // namespace android
+12 −1
Original line number Diff line number Diff line
@@ -53,7 +53,10 @@ public:

    virtual ~AudioStreamOut() { }

    virtual status_t getRenderPosition(uint32_t *frames);
    // Get the bottom 32-bits of the 64-bit render position.
    status_t getRenderPosition(uint32_t *frames);

    virtual status_t getRenderPosition(uint64_t *frames);

    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);

@@ -76,6 +79,14 @@ public:

    virtual status_t flush();
    virtual status_t standby();

protected:
    uint64_t             mFramesWritten; // reset by flush
    uint64_t             mFramesWrittenAtStandby;
    uint64_t             mRenderPosition; // reset by flush or standby
    int                  mRateMultiplier;
    bool                 mHalFormatIsLinearPcm;
    size_t               mHalFrameSize;
};

} // namespace android
+0 −47
Original line number Diff line number Diff line
@@ -36,10 +36,7 @@ SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev,
            audio_output_flags_t flags,
            audio_format_t format)
        : AudioStreamOut(dev,flags)
        , mRateMultiplier(1)
        , mSpdifEncoder(this, format)
        , mRenderPositionHal(0)
        , mPreviousHalPosition32(0)
{
}

@@ -97,62 +94,18 @@ status_t SpdifStreamOut::open(
    return status;
}

// Account for possibly higher sample rate.
status_t SpdifStreamOut::getRenderPosition(uint32_t *frames)
{
    uint32_t halPosition = 0;
    status_t status = AudioStreamOut::getRenderPosition(&halPosition);
    if (status != NO_ERROR) {
        return status;
    }

    // Accumulate a 64-bit position so that we wrap at the right place.
    if (mRateMultiplier != 1) {
        // Maintain a 64-bit render position.
        int32_t deltaHalPosition = (int32_t)(halPosition - mPreviousHalPosition32);
        mPreviousHalPosition32 = halPosition;
        mRenderPositionHal += deltaHalPosition;

        // Scale from device sample rate to application rate.
        uint64_t renderPositionApp = mRenderPositionHal / mRateMultiplier;
        ALOGV("SpdifStreamOut::getRenderPosition() "
            "renderPositionAppRate = %llu = %llu / %u\n",
            renderPositionApp, mRenderPositionHal, mRateMultiplier);

        *frames = (uint32_t)renderPositionApp;
    } else {
        *frames = halPosition;
    }
    return status;
}

int SpdifStreamOut::flush()
{
    mSpdifEncoder.reset();
    mRenderPositionHal = 0;
    mPreviousHalPosition32 = 0;
    return AudioStreamOut::flush();
}

int SpdifStreamOut::standby()
{
    mSpdifEncoder.reset();
    mRenderPositionHal = 0;
    mPreviousHalPosition32 = 0;
    return AudioStreamOut::standby();
}

// Account for possibly higher sample rate.
// This is much easier when all the values are 64-bit.
status_t SpdifStreamOut::getPresentationPosition(uint64_t *frames,
        struct timespec *timestamp)
{
    uint64_t halFrames = 0;
    status_t status = AudioStreamOut::getPresentationPosition(&halFrames, timestamp);
    *frames = halFrames / mRateMultiplier;
    return status;
}

size_t SpdifStreamOut::getFrameSize()
{
    return sizeof(int8_t);
+0 −9
Original line number Diff line number Diff line
@@ -49,10 +49,6 @@ public:
            struct audio_config *config,
            const char *address);

    virtual status_t getRenderPosition(uint32_t *frames);

    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);

    /**
    * Write audio buffer to driver. Returns number of bytes written, or a
    * negative status_t. If at least one frame was written successfully prior to the error,
@@ -92,13 +88,8 @@ private:
        SpdifStreamOut * const mSpdifStreamOut;
    };

    int                  mRateMultiplier;
    MySPDIFEncoder       mSpdifEncoder;

    // Used to implement getRenderPosition()
    int64_t              mRenderPositionHal;
    uint32_t             mPreviousHalPosition32;

    ssize_t  writeDataBurst(const void* data, size_t bytes);
    ssize_t  writeInternal(const void* buffer, size_t bytes);