Loading services/audioflinger/PatchPanel.cpp +38 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading services/audioflinger/TrackBase.h +14 −2 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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. Loading services/audioflinger/Tracks.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -1886,6 +1896,16 @@ void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo( int64_t trackFramesReleased, int64_t sourceFramesRead, uint32_t halSampleRate, const ExtendedTimestamp ×tamp) { // 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. Loading Loading
services/audioflinger/PatchPanel.cpp +38 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading
services/audioflinger/TrackBase.h +14 −2 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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. Loading
services/audioflinger/Tracks.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -1886,6 +1896,16 @@ void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo( int64_t trackFramesReleased, int64_t sourceFramesRead, uint32_t halSampleRate, const ExtendedTimestamp ×tamp) { // 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. Loading