author | Paul Adenot <paul@paul.cx> |
Thu, 28 May 2020 09:50:20 +0000 | |
changeset 532722 | 61336bfc758449a130882874551df6c358ecd0ae |
parent 532721 | 3a5f3040fbef3e0c98aa1462c5c3525b96e3a76d |
child 532723 | 99be85a6ec5c09982fbda237c9c5c9d80889473d |
push id | 37457 |
push user | nerli@mozilla.com |
push date | Thu, 28 May 2020 15:51:15 +0000 |
treeherder | mozilla-central@272e3c98d002 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | achronop |
bugs | 1628779 |
milestone | 78.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -1227,16 +1227,27 @@ TimeDuration AudioCallbackDriver::AudioO if (rv || mSampleRate == 0) { return TimeDuration::FromSeconds(0.0); } return TimeDuration::FromSeconds(static_cast<double>(latencyFrames) / 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<double>(latencyFrames) / + mSampleRate); +} + void AudioCallbackDriver::FallbackToSystemClockDriver() { MOZ_ASSERT(!ThreadRunning()); MOZ_ASSERT(mAudioStreamState == AudioStreamState::None || mAudioStreamState == AudioStreamState::Errored || mAudioStreamState == AudioStreamState::Pending); MOZ_ASSERT(mFallbackDriverState == FallbackDriverState::None); LOG(LogLevel::Debug, ("%p: AudioCallbackDriver %p Falling back to SystemClockDriver.", Graph(),
--- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -641,16 +641,18 @@ class AudioCallbackDriver : public Graph /* Whether the underlying cubeb stream has been started. See comment for * mStarted for details. */ bool IsStarted(); void CompleteAudioContextOperations(AsyncCubebOperation aOperation); // 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: /** * On certain MacBookPro, the microphone is located near the left speaker. * We need to pan the sound output to the right speaker if we are using the * mic and the built-in speaker, or we will have terrible echo. */ void PanOutputIfNeeded(bool aMicrophoneActive); /**
--- a/dom/media/MediaTrackGraph.cpp +++ b/dom/media/MediaTrackGraph.cpp @@ -905,19 +905,19 @@ void MediaTrackGraphImpl::DeviceChanged( // This is a special case where the origin of this event cannot control the // lifetime of the graph, because the graph is controling the lifetime of // the AudioCallbackDriver where the event originated. // We know the graph is soon going away, so there's no need to notify about // this device change. 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 // the graph, with the new info. RefPtr<MediaTrackGraphImpl> self = this; NS_DispatchBackgroundTask(NS_NewRunnableFunction( "MaxChannelCountUpdateOnBgThread", [self{move(self)}]() { uint32_t maxChannelCount = CubebUtils::MaxNumberOfChannels(); @@ -1682,16 +1682,21 @@ void MediaTrackGraphImpl::RunInStableSta "LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP", "LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN", "LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION"}; if (LifecycleStateRef() != LIFECYCLE_RUNNING) { 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); for (uint32_t i = 0; i < mTrackUpdates.Length(); ++i) { TrackUpdate* update = &mTrackUpdates[i]; if (update->mTrack) { ApplyTrackUpdate(update); } @@ -2982,16 +2987,17 @@ MediaTrackGraphImpl::MediaTrackGraphImpl mGlobalVolume(CubebUtils::GetVolumeScale()) #ifdef DEBUG , mCanRunMessagesSynchronously(false) #endif , 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. mLifecycleState = LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION; #ifdef DEBUG mCanRunMessagesSynchronously = true; #endif return; @@ -3619,37 +3625,53 @@ uint32_t MediaTrackGraphImpl::AudioOutpu if (CurrentDriver()->AsAudioCallbackDriver()) { return CurrentDriver()->AsAudioCallbackDriver()->OutputChannelCount(); } return 2; } } double MediaTrackGraph::AudioOutputLatency() { - return static_cast<MediaTrackGraphImpl*>(this)->AudioOutputLatency(); + return static_cast<MediaTrackGraphImpl*>(this)->CachedAudioOutputLatency(); } -double MediaTrackGraphImpl::AudioOutputLatency() { +double MediaTrackGraphImpl::CachedAudioOutputLatency() { + MOZ_ASSERT(NS_IsMainThread()); + return mAudioOutputLatency; +} + +double MediaTrackGraphImpl::CachedAudioInputLatency() { 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 mAudioInputLatency; +} + +void MediaTrackGraphImpl::UpdateAudioLatencies() { + RefPtr<MediaTrackGraphImpl> 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<const MediaTrackGraphImpl*>(this)->mRealtime; } void MediaTrackGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess) { MOZ_ASSERT(NS_IsMainThread(), "main thread only");
--- a/dom/media/MediaTrackGraphImpl.h +++ b/dom/media/MediaTrackGraphImpl.h @@ -491,17 +491,24 @@ class MediaTrackGraphImpl : public Media mTrackOrderDirty = true; } // Get the current maximum channel count. Graph thread only. uint32_t AudioOutputChannelCount() const; // 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 * channel counts requested by the listeners. The max channel count is * delivered to the listeners themselves, and they take care of downmixing. */ uint32_t AudioInputChannelCount() { MOZ_ASSERT(OnGraphThreadOrNotRunning()); @@ -1019,20 +1026,36 @@ class MediaTrackGraphImpl : public Media /** * Set based on mProcessedTime at end of iteration. * Read by stable state runnable on main thread. Protected by mMonitor. */ 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. + */ + std::atomic<double> mAudioOutputLatency; + /** + * Cached audio input latency, in seconds. This is reset * whenever the audio device running this MediaTrackGraph changes. */ - double mAudioOutputLatency; + std::atomic<double> 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 * supports. This is cached here because it can be expensive to query. The * cache is invalidated when the device is changed. This is initialized in the * ctor, and the read/write only on the graph thread. */ uint32_t mMaxOutputChannelCount;