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
This commit is contained in:
Paul Adenot 2020-05-28 09:50:20 +00:00
Родитель 25413bb019
Коммит 3eb71b17bf
4 изменённых файлов: 79 добавлений и 21 удалений

Просмотреть файл

@ -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<double>(latencyFrames) /
mSampleRate);
}
void AudioCallbackDriver::FallbackToSystemClockDriver() {
MOZ_ASSERT(!ThreadRunning());
MOZ_ASSERT(mAudioStreamState == AudioStreamState::None ||

Просмотреть файл

@ -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:
/**

Просмотреть файл

@ -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,27 +3630,43 @@ uint32_t MediaTrackGraphImpl::AudioOutputChannelCount() const {
}
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());
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;
}
}
double MediaTrackGraphImpl::CachedAudioInputLatency() {
MOZ_ASSERT(NS_IsMainThread());
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;

Просмотреть файл

@ -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<double> mAudioOutputLatency;
/**
* Cached audio input latency, in seconds. This is reset
* whenever the audio device running this MediaTrackGraph changes.
*/
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