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

Commit e4b4971a authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

audio: Implement more accurate timing for the stub stream

Stub output stream is like a /dev/null audio device, however
for synchronous transfers it must block for the duration of
the audio chunk being transferred. Implement more accurate
accounting for the blocking time using the same approach as
employed by the remote submix stream implementation.

Bug: 356719263
Test: atest CtsNativeMediaAAudioTestCases
      on aosp_cf_x86_64_auto target
(cherry picked from https://android-review.googlesource.com/q/commit:10fc96386edfa98fea9c5a2a35146f9a2d1efe31)
Merged-In: I137aed397246bcf2b5ef6789aa4d2d27ead64467
Change-Id: I137aed397246bcf2b5ef6789aa4d2d27ead64467
parent 01df7e8c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -44,6 +44,10 @@ class StreamStub : public StreamCommonImpl {
    const bool mIsInput;
    bool mIsInitialized = false;  // Used for validating the state machine logic.
    bool mIsStandby = true;       // Used for validating the state machine logic.

    // Used by the worker thread.
    int64_t mStartTimeNs = 0;
    long mFramesSinceStart = 0;
};

class StreamInStub final : public StreamIn, public StreamStub {
+16 −8
Original line number Diff line number Diff line
@@ -83,7 +83,6 @@ StreamStub::~StreamStub() {
    if (!mIsInitialized) {
        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
    }
    usleep(500);
    mIsStandby = true;
    return ::android::OK;
}
@@ -92,8 +91,9 @@ StreamStub::~StreamStub() {
    if (!mIsInitialized) {
        LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
    }
    usleep(500);
    mIsStandby = false;
    mStartTimeNs = ::android::uptimeNanos();
    mFramesSinceStart = 0;
    return ::android::OK;
}

@@ -105,14 +105,23 @@ StreamStub::~StreamStub() {
    if (mIsStandby) {
        LOG(FATAL) << __func__ << ": must not happen while in standby";
    }
    static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
    static constexpr float kScaleFactor = .8f;
    *actualFrameCount = frameCount;
    if (mIsAsynchronous) {
        usleep(500);
    } else {
        const size_t delayUs = static_cast<size_t>(
                std::roundf(kScaleFactor * frameCount * kMicrosPerSecond / mSampleRate));
        usleep(delayUs);
        mFramesSinceStart += *actualFrameCount;
        const long bufferDurationUs =
                (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
        const auto totalDurationUs =
                (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
        const long totalOffsetUs =
                mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
        LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
        if (totalOffsetUs > 0) {
            const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
            LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
            usleep(sleepTimeUs);
        }
    }
    if (mIsInput) {
        uint8_t* byteBuffer = static_cast<uint8_t*>(buffer);
@@ -120,7 +129,6 @@ StreamStub::~StreamStub() {
            byteBuffer[i] = std::rand() % 255;
        }
    }
    *actualFrameCount = frameCount;
    return ::android::OK;
}