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

Commit 8062a773 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge "audio: Adjust default impl for non-RT audio behavior of AVD" into main

parents cf5c2cf4 6c419352
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -27,13 +27,18 @@ class StreamPrimary : public StreamAlsa {
  public:
    StreamPrimary(StreamContext* context, const Metadata& metadata);

    ::android::status_t start() override;
    ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                 int32_t* latencyMs) override;
    ::android::status_t refinePosition(StreamDescriptor::Position* position) override;

  protected:
    std::vector<alsa::DeviceProfile> getDeviceProfiles() override;

    const bool mIsAsynchronous;
    long mStartTimeNs = 0;
    long mFramesSinceStart = 0;
    bool mSkipNextTransfer = false;
};

class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
+42 −17
Original line number Diff line number Diff line
@@ -14,12 +14,11 @@
 * limitations under the License.
 */

#include <chrono>

#define LOG_TAG "AHAL_StreamPrimary"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <audio_utils/clock.h>
#include <error/Result.h>
#include <error/expected_utils.h>

#include "PrimaryMixer.h"
@@ -43,26 +42,52 @@ StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
    context->startStreamDataProcessor();
}

::android::status_t StreamPrimary::start() {
    RETURN_STATUS_IF_ERROR(StreamAlsa::start());
    mStartTimeNs = ::android::uptimeNanos();
    mFramesSinceStart = 0;
    mSkipNextTransfer = false;
    return ::android::OK;
}

::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
                                            size_t* actualFrameCount, int32_t* latencyMs) {
    auto start = std::chrono::steady_clock::now();
    if (auto status = StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs);
        status != ::android::OK) {
        return status;
    }
    // This is a workaround for the emulator implementation which has a host-side buffer
    // and this can result in reading faster than real time.
    if (mIsInput && !mIsAsynchronous) {
        auto recordDurationUs = std::chrono::duration_cast<std::chrono::microseconds>(
                std::chrono::steady_clock::now() - start);
        const long projectedVsObservedOffsetUs =
                *actualFrameCount * MICROS_PER_SECOND / mContext.getSampleRate() -
                recordDurationUs.count();
        if (projectedVsObservedOffsetUs > 0) {
            LOG(VERBOSE) << __func__ << ": sleeping for " << projectedVsObservedOffsetUs << " us";
            usleep(projectedVsObservedOffsetUs);
    // and is not being able to achieve real-time behavior similar to ADSPs (b/302587331).
    if (!mSkipNextTransfer) {
        RETURN_STATUS_IF_ERROR(
                StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs));
    } else {
        LOG(DEBUG) << __func__ << ": skipping transfer (" << frameCount << " frames)";
        *actualFrameCount = frameCount;
        if (mIsInput) memset(buffer, 0, frameCount);
        mSkipNextTransfer = false;
    }
    if (!mIsAsynchronous) {
        const long bufferDurationUs =
                (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
        const auto totalDurationUs =
                (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
        mFramesSinceStart += *actualFrameCount;
        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);
        } else {
            mSkipNextTransfer = true;
        }
    } else {
        LOG(VERBOSE) << __func__ << ": asynchronous transfer";
    }
    return ::android::OK;
}

::android::status_t StreamPrimary::refinePosition(StreamDescriptor::Position*) {
    // Since not all data is actually sent to the HAL, use the position maintained by Stream class
    // which accounts for all frames passed from / to the client.
    return ::android::OK;
}