Closed Bug 1897328 Opened 1 year ago Closed 1 year ago

smooth buffering level input to DriftController

Categories

(Core :: WebRTC: Audio/Video, enhancement)

enhancement

Tracking

()

RESOLVED FIXED
130 Branch
Tracking Status
firefox130 --- fixed

People

(Reporter: karlt, Assigned: karlt)

References

Details

Attachments

(12 files, 1 obsolete file)

79.04 KB, text/html
Details
92.35 KB, text/html
Details
82.97 KB, text/html
Details
462.30 KB, text/html
Details
417.92 KB, text/html
Details
100.93 KB, text/html
Details
89.42 KB, text/html
Details
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review

Variations in the timing and size of audio packets can cause fluctuations in the AudioDriftCorrection buffering level, to which DriftController responds with unnecessary changes in the resampling rate. Such changes can be large enough to degrade echo canceller performance.

The variations can be due to

  • Differences between input and output callback frequency or timing.
  • Rounding to 128-frame chunks for the MediaTrackGraph and Web Audio.
  • Inconsistent packet sizes from the system audio callback. This seems particularly common with a pulseaudio server. (Pipewire was much more consistent.) It was observed with an Intel 100 Series/C230 Series Chipset Family HD Audio Controller, but not with a bluetooth speaker.
    Doubling minreq to tlength / 4, as suggested in the commit message of https://github.com/mozilla/cubeb-pulse-rs/commit/ee66661422726f6db781c9043de90ccec4e3520a, changed the pattern, but packets were still irregularly size. Perhaps larger packets could be written than requested, but this would have an effect on latency.
    Evidence of chunk or packet size differences can be observed to some extent in the "In latency" and "Out latency" plots linked from bug 1890467 comment 1, which variables are 5-point equal-weighted FIR moving averages of frame counts between each output request.

The variations are short term and often oscillatory, and so low-pass filter smoothing would reduce their effect.

A naive smoothing of the effects of the PID controller would make the controller unstable due to the delay in feedback.

Depends on: 1899189

The attached plot is from a system with pulseaudio. The DriftController sat between a graph running at 48kHz and a secondary audio output (from setSinkId()) running at 44.1kHz. The "media.cubeb.force_sample_rate" pref can be useful to configure the graph for a rate different to the preferred rate of an output device.

With smoothing, the variability in the configured in sample rate is reduced by enough that the responses to changes in desired buffering dominate.
The graphs may be zoomed to see the variations in configured in sample rate.

The configured resampling rate and actual buffering in TestDriftController.LargeStepResponse (a new test to be added here) are similar with and without smoothing of the buffer level because the buffer level is smooth. This plot is for the controller with smoothing.

The caps on the changes in the configured resampling rate delay the response of the PID controller, causing large oscillations.

After replacing the integral term of the PID controller with a clock drift estimate, the oscillations attenuate much faster.

Replacing the integral term with the drift estimate does not have a significant effect on the variability in configured in sample rate.

The DriftController will be modified in a subsequent patch to use these values.

Depends on D215484

An average buffering level estimate is used as input to the PID controller.
This estimate is updated for known changes in resampling (control signal
feedback) and for an estimated drift rate.

The hysteresis band is reduced because the average buffer level is less
variable. The hysteresis band must be smaller for the instantaneous error to
remain within its (wider) band for assessing whether to reduce the desired
buffer level.

The number of iterations is increased with a smaller output packet size in
several TestDriftController tests so that buffer level changes are reflected
in its moving average faster. The controller intentionally does not respond
as much to variations in a small number of buffering level data points.

An extra second is added to TestDriftController.VerySmallBufferedFrames
because, as the corrected rate gets very small, the input packet durations are
sometimes zero and the corrected rate does not get updated when the input
packet is zero.

TestAudioDriftCorrection.DriftStepResponseUnderrunHighLatencyInput has higher
actual buffering before the missing input segment, and so takes longer to
underrun.

TestAudioDriftCorrection.DynamicInputBufferSizeChanges was still adjusting the
desired buffering level at the end of the test, both before and after this
change, but the narrower hysteresis is less tolerant of desired buffer level
changes.

Depends on D215485

The drift estimate is not affected by feedback from the PD controller and so
does not have the same stability risks as the integral term, such as integral
wind up while the change in response is being capped. The response while not
capped and outside hysteresis is now purely an exponential decay, no longer
with an oscillatory component. When the capping is applied, the lag in
adjustment still causes some oscillations from overshoot, but these now
attenuate much faster.

If the drift estimate applied to the corrected rate is accurate enough, then
the desired steady state contribution from the remaining terms approaches zero
as the error approaches zero, so the integral term is no longer required.

The rate at which the drift estimate adjusts to changes in input depends on
packet rate. For typical low latency packet sizes, the drift estimate should
adjust faster than the integral term. This makes the controller more
resistant to underrun in TestAudioDriftCorrection.DriftStepResponseUnderrun,
which is adjusted according.

The clock drift estimate does not anticipate ongoing desired buffer level
changes like the intergral term did, and so
TestAudioDriftCorrection.DynamicInputBufferSizeChanges does not reach the
hysteresis band by the end of the test.

TestDriftController.VerySmallBufferedFrames now runs slightly longer because
the rate of change in correction is not quite as steep as the capped rate.

Depends on D215486

Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/28378fd26a21 Remove unused MediaTrackGraphImpl::mIterationEndTime r=padenot https://hg.mozilla.org/integration/autoland/rev/6c5306138d62 Add a profiling marker to trace the period rendered by the MediaTrackGraph r=padenot
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/63258b634468 Provide input durations to DriftController tests that are consistent with the buffering levels r=pehrsons
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/432ef28ef357 Smooth buffering level input to DriftController r=pehrsons
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/545e985e2428 Replace integral controller term with clock drift estimate r=pehrsons
Status: ASSIGNED → RESOLVED
Closed: 1 year ago
Resolution: --- → FIXED
Target Milestone: --- → 130 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: