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

Commit 73af62a5 authored by Phil Burk's avatar Phil Burk
Browse files

aaudio: fix loss of sync with HW FIFO index

This fixes a problem with intermittent severe distortion
and variable latency after restarting a stream.

Bug: 68003241
Test: write_sine_callback -pl -m2 -n2 -s5 -c2 -l100
Change-Id: Id7418adb86f2869ac74936cfbd365815a0a0e923
parent 442459bc
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -89,6 +89,18 @@ public:
        mCounter32 = 0;
    }

    /**
     * Round 64-bit counter up to a multiple of the period.
     *
     * @param period might be, for example, a buffer capacity
     */
    void roundUp64(int32_t period) {
        if (period > 0) {
            int64_t numPeriods = (mCounter64 + period - 1) / period;
            mCounter64 = numPeriods * period;
        }
    }

private:
    int64_t mCounter64 = 0;
    int32_t mCounter32 = 0;
+7 −0
Original line number Diff line number Diff line
@@ -258,6 +258,13 @@ aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBas
aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
                                                  audio_port_handle_t clientHandle) {
    mFramesTransferred.reset32();

    // Round 64-bit counter up to a multiple of the buffer capacity.
    // This is required because the 64-bit counter is used as an index
    // into a circular buffer and the actual HW position is reset to zero
    // when the stream is stopped.
    mFramesTransferred.roundUp64(getBufferCapacity());

    return stopClient(mPortHandle);
}

+13 −7
Original line number Diff line number Diff line
@@ -202,19 +202,23 @@ aaudio_result_t AAudioServiceStreamBase::pause() {
        ALOGE("AAudioServiceStreamShared::pause() missing endpoint");
        return AAUDIO_ERROR_INVALID_STATE;
    }
    result = mServiceEndpoint->stopStream(this, mClientHandle);
    if (result != AAUDIO_OK) {
        ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
        disconnect(); // TODO should we return or pause Base first?
    }

    // Send it now because the timestamp gets rounded up when stopStream() is called below.
    // Also we don't need the timestamps while we are shutting down.
    sendCurrentTimestamp();
    mThreadEnabled.store(false);
    result = mTimestampThread.stop();

    result = stopTimestampThread();
    if (result != AAUDIO_OK) {
        disconnect();
        return result;
    }

    result = mServiceEndpoint->stopStream(this, mClientHandle);
    if (result != AAUDIO_OK) {
        ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
        disconnect(); // TODO should we return or pause Base first?
    }

    sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
    setState(AAUDIO_STREAM_STATE_PAUSED);
    return result;
@@ -233,6 +237,8 @@ aaudio_result_t AAudioServiceStreamBase::stop() {

    setState(AAUDIO_STREAM_STATE_STOPPING);

    // Send it now because the timestamp gets rounded up when stopStream() is called below.
    // Also we don't need the timestamps while we are shutting down.
    sendCurrentTimestamp(); // warning - this calls a virtual function
    result = stopTimestampThread();
    if (result != AAUDIO_OK) {