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

Commit 3a1a0b5d authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "AudioFlinger: Add patch latency for direct record/playback"

parents 6e880c55 30282562
Loading
Loading
Loading
Loading
+38 −6
Original line number Diff line number Diff line
@@ -547,15 +547,47 @@ status_t AudioFlinger::PatchPanel::Patch::getLatencyMs(double *latencyMs) const
    // reverse due to internal biases).
    //
    // TODO: is this stable enough? Consider a PatchTrack synchronized version of this.
    double recordServerLatencyMs;
    if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) != OK) return INVALID_OPERATION;

    double playbackTrackLatencyMs;
    if (playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) != OK) return INVALID_OPERATION;

    // For PCM tracks get server latency.
    if (audio_is_linear_pcm(recordTrack->format())) {
        double recordServerLatencyMs, playbackTrackLatencyMs;
        if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) == OK
                && playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) == OK) {
            *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
            return OK;
        }
    }

    // See if kernel latencies are available.
    // If so, do a frame diff and time difference computation to estimate
    // the total patch latency. This requires that frame counts are reported by the
    // HAL are matched properly in the case of record overruns and playback underruns.
    ThreadBase::TrackBase::FrameTime recordFT{}, playFT{};
    recordTrack->getKernelFrameTime(&recordFT);
    playbackTrack->getKernelFrameTime(&playFT);
    if (recordFT.timeNs > 0 && playFT.timeNs > 0) {
        const int64_t frameDiff = recordFT.frames - playFT.frames;
        const int64_t timeDiffNs = recordFT.timeNs - playFT.timeNs;

        // It is possible that the patch track and patch record have a large time disparity because
        // one thread runs but another is stopped.  We arbitrarily choose the maximum timestamp
        // time difference based on how often we expect the timestamps to update in normal operation
        // (typical should be no more than 50 ms).
        //
        // If the timestamps aren't sampled close enough, the patch latency is not
        // considered valid.
        //
        // TODO: change this based on more experiments.
        constexpr int64_t maxValidTimeDiffNs = 200 * NANOS_PER_MILLISECOND;
        if (std::abs(timeDiffNs) < maxValidTimeDiffNs) {
            *latencyMs = frameDiff * 1e3 / recordTrack->sampleRate()
                   - timeDiffNs * 1e-6;
            return OK;
        }
    }

    return INVALID_OPERATION;
}

String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
{
+14 −2
Original line number Diff line number Diff line
@@ -187,6 +187,19 @@ public:
                            return status;
                        }

           // TODO: Consider making this external.
           struct FrameTime {
               int64_t frames;
               int64_t timeNs;
           };

           // KernelFrameTime is updated per "mix" period even for non-pcm tracks.
           void         getKernelFrameTime(FrameTime *ft) const {
                           *ft = mKernelFrameTime.load();
                        }

           audio_format_t format() const { return mFormat; }

protected:
    DISALLOW_COPY_AND_ASSIGN(TrackBase);

@@ -198,8 +211,6 @@ protected:
    // but putting it in TrackBase avoids the complexity of virtual inheritance
    virtual size_t  framesReady() const { return SIZE_MAX; }

    audio_format_t format() const { return mFormat; }

    uint32_t channelCount() const { return mChannelCount; }

    audio_channel_mask_t channelMask() const { return mChannelMask; }
@@ -307,6 +318,7 @@ protected:
    bool                mServerLatencySupported = false;
    std::atomic<bool>   mServerLatencyFromTrack{}; // latency from track or server timestamp.
    std::atomic<double> mServerLatencyMs{};        // last latency pushed from server thread.
    std::atomic<FrameTime> mKernelFrameTime{};     // last frame time on kernel side.
};

// PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
+20 −0
Original line number Diff line number Diff line
@@ -1258,6 +1258,16 @@ void AudioFlinger::PlaybackThread::Track::resumeAck() {
void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
        int64_t trackFramesReleased, int64_t sinkFramesWritten,
        uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
   // Make the kernel frametime available.
    const FrameTime ft{
            timeStamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
            timeStamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
    // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
    mKernelFrameTime.store(ft);
    if (!audio_is_linear_pcm(mFormat)) {
        return;
    }

    //update frame map
    mFrameMap.push(trackFramesReleased, sinkFramesWritten);

@@ -1886,6 +1896,16 @@ void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo(
        int64_t trackFramesReleased, int64_t sourceFramesRead,
        uint32_t halSampleRate, const ExtendedTimestamp &timestamp)
{
   // Make the kernel frametime available.
    const FrameTime ft{
            timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
            timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
    // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
    mKernelFrameTime.store(ft);
    if (!audio_is_linear_pcm(mFormat)) {
        return;
    }

    ExtendedTimestamp local = timestamp;

    // Convert HAL frames to server-side track frames at track sample rate.