From 3eb71b17bf4a401516dad25cd9114ff19ed0bfee Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Thu, 28 May 2020 09:50:20 +0000 Subject: [PATCH] Bug 1628779 - Update the latency periodically on main thread. r=achronop We're doing it async, triggered during the stable state runnable, and then the values are cached in atomic variables, so that the rendering thread can have the info as well, for using during processing. Differential Revision: https://phabricator.services.mozilla.com/D75331 --- dom/media/GraphDriver.cpp | 11 +++++++ dom/media/GraphDriver.h | 2 ++ dom/media/MediaTrackGraph.cpp | 58 +++++++++++++++++++++++---------- dom/media/MediaTrackGraphImpl.h | 29 +++++++++++++++-- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index ef8f15f98b04..bf8eba83b564 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -1232,6 +1232,17 @@ TimeDuration AudioCallbackDriver::AudioOutputLatency() { mSampleRate); } +TimeDuration AudioCallbackDriver::AudioInputLatency() { + uint32_t latencyFrames; + int rv = cubeb_stream_get_input_latency(mAudioStream, &latencyFrames); + if (rv || mSampleRate == 0) { + return TimeDuration::FromSeconds(0.0); + } + + return TimeDuration::FromSeconds(static_cast(latencyFrames) / + mSampleRate); +} + void AudioCallbackDriver::FallbackToSystemClockDriver() { MOZ_ASSERT(!ThreadRunning()); MOZ_ASSERT(mAudioStreamState == AudioStreamState::None || diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index aa032b5c19b2..c601f5910578 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -646,6 +646,8 @@ class AudioCallbackDriver : public GraphDriver, // Returns the output latency for the current audio output stream. TimeDuration AudioOutputLatency(); + // Returns the input latency for the current audio output stream. + TimeDuration AudioInputLatency(); private: /** diff --git a/dom/media/MediaTrackGraph.cpp b/dom/media/MediaTrackGraph.cpp index 63175d301231..59434ede585c 100644 --- a/dom/media/MediaTrackGraph.cpp +++ b/dom/media/MediaTrackGraph.cpp @@ -910,9 +910,9 @@ void MediaTrackGraphImpl::DeviceChanged() { return; } - // Reset the latency, it will get fetched again next time it's queried. MOZ_ASSERT(NS_IsMainThread()); - mAudioOutputLatency = 0.0; + // Have the latency re-queried next stable state. + mLatencyQueryCounter = LATENCY_QUERYING_INTERVAL; // Dispatch to the bg thread to do the (potentially expensive) query of the // maximum channel count, and then dispatch back to the main thread, then to @@ -1687,6 +1687,11 @@ void MediaTrackGraphImpl::RunInStableState(bool aSourceIsMTG) { LOG(LogLevel::Debug, ("%p: Running stable state callback. Current state: %s", this, LifecycleState_str[LifecycleStateRef()])); + } else { + if (mLatencyQueryCounter++ == LATENCY_QUERYING_INTERVAL) { + UpdateAudioLatencies(); + mLatencyQueryCounter = 0; + } } runnables.SwapElements(mUpdateRunnables); @@ -2987,6 +2992,7 @@ MediaTrackGraphImpl::MediaTrackGraphImpl( , mMainThreadGraphTime(0, "MediaTrackGraphImpl::mMainThreadGraphTime"), mAudioOutputLatency(0.0), + mAudioInputLatency(0.0), mMaxOutputChannelCount(std::min(8u, CubebUtils::MaxNumberOfChannels())) { if (aRunTypeRequested == SINGLE_THREAD && !mGraphRunner) { // Failed to create thread. Jump to the last phase of the lifecycle. @@ -3624,28 +3630,44 @@ uint32_t MediaTrackGraphImpl::AudioOutputChannelCount() const { } double MediaTrackGraph::AudioOutputLatency() { - return static_cast(this)->AudioOutputLatency(); + return static_cast(this)->CachedAudioOutputLatency(); } -double MediaTrackGraphImpl::AudioOutputLatency() { +double MediaTrackGraphImpl::CachedAudioOutputLatency() { MOZ_ASSERT(NS_IsMainThread()); - if (mAudioOutputLatency != 0.0) { - return mAudioOutputLatency; - } - MonitorAutoLock lock(mMonitor); - if (CurrentDriver()->AsAudioCallbackDriver()) { - mAudioOutputLatency = CurrentDriver() - ->AsAudioCallbackDriver() - ->AudioOutputLatency() - .ToSeconds(); - } else { - // Failure mode: return 0.0 if running on a normal thread. - mAudioOutputLatency = 0.0; - } - return mAudioOutputLatency; } +double MediaTrackGraphImpl::CachedAudioInputLatency() { + MOZ_ASSERT(NS_IsMainThread()); + return mAudioInputLatency; +} + +void MediaTrackGraphImpl::UpdateAudioLatencies() { + RefPtr self = this; + NS_DispatchBackgroundTask( + NS_NewRunnableFunction("UpdateLatency", [self{std::move(self)}]() { + MonitorAutoLock lock(self->mMonitor); + if (self->CurrentDriver()->AsAudioCallbackDriver()) { + AudioCallbackDriver* driver = + self->CurrentDriver()->AsAudioCallbackDriver(); + if (driver->InputChannelCount()) { + self->mAudioInputLatency = driver->AudioInputLatency().ToSeconds(); + } + self->mAudioOutputLatency = driver->AudioOutputLatency().ToSeconds(); + } + })); +} + +double MediaTrackGraphImpl::AudioOutputLatencyGraphThread() { + AssertOnGraphThreadOrNotRunning(); + return mAudioOutputLatency; +} +double MediaTrackGraphImpl::AudioInputLatencyGraphThread() { + AssertOnGraphThreadOrNotRunning(); + return mAudioInputLatency; +} + bool MediaTrackGraph::IsNonRealtime() const { return !static_cast(this)->mRealtime; } diff --git a/dom/media/MediaTrackGraphImpl.h b/dom/media/MediaTrackGraphImpl.h index d776f2e57ec8..2ccd10431637 100644 --- a/dom/media/MediaTrackGraphImpl.h +++ b/dom/media/MediaTrackGraphImpl.h @@ -496,7 +496,14 @@ class MediaTrackGraphImpl : public MediaTrackGraph, // Set a new maximum channel count. Graph thread only. void SetMaxOutputChannelCount(uint32_t aMaxChannelCount); - double AudioOutputLatency(); + // Main thread only, query and update the cached latency figure. + double CachedAudioOutputLatency(); + double CachedAudioInputLatency(); + void UpdateAudioLatencies(); + + // Graph thread only, get the cached latency figure. + double AudioOutputLatencyGraphThread(); + double AudioInputLatencyGraphThread(); /** * The audio input channel count for a MediaTrackGraph is the max of all the @@ -1024,10 +1031,26 @@ class MediaTrackGraphImpl : public MediaTrackGraph, GraphTime mNextMainThreadGraphTime = 0; /** - * Cached audio output latency, in seconds. Main thread only. This is reset + * Cached audio output latency, in seconds. This is reset * whenever the audio device running this MediaTrackGraph changes. */ - double mAudioOutputLatency; + std::atomic mAudioOutputLatency; + /** + * Cached audio input latency, in seconds. This is reset + * whenever the audio device running this MediaTrackGraph changes. + */ + std::atomic mAudioInputLatency; + + /** + * Only query the latency once every LATENCY_QUERYING_INTERVAL stable state. + */ + const uint32_t LATENCY_QUERYING_INTERVAL = 100; + + /** + * Counter to only query the audio latencies every N iterations. Main thread + * only. + */ + uint32_t mLatencyQueryCounter = 0; /** * The max audio output channel count the default audio output device