When playing audio through WebAudio, we want to be able to measure the delay of that audio and the glitchiness of the audio. This document contains a proposal of an API that would allow WebAudio users to do this.
This is an unofficial proposal.
There is currently no way to detect whether WebAudio playout has glitches (gaps in the played audio, which typically happens due to underperformance in the audio pipeline). There is an existing way to measure the instantaneous playout latency using AudioContext.outputLatency, but no simple way to measure average/minimum/maximum latency over time.
Glitches and high latency are bad for the user experience, so if any of these occur it can be useful for the application to be able to detect this and possibly take some action to improve the playout.
partial interface AudioContext { [SameObject] readonly attribute AudioPlayoutStats playoutStats; };
The {{AudioContext/AudioPlayoutStats}} under AudioContext is a dedicated object for statistics reporting;
Similar to RTCAudioPlayoutStats,
but it is for the playout path via AudioDestinationNode and the associated output device.
This will allow us to measure glitches occurring due to underperforming AudioWorklets as well as glitches and
delay occurring in the playout path between the AudioContext and the output device.Attributes
playoutStats attribute
[Exposed=Window, SecureContext] interface AudioPlayoutStats { readonly attribute DOMHighResTimeStamp fallbackFramesDuration; readonly attribute unsigned long fallbackFramesEvents; readonly attribute DOMHighResTimeStamp totalFramesDuration; readonly attribute DOMHighResTimeStamp averageLatency; readonly attribute DOMHighResTimeStamp minimumLatency; readonly attribute DOMHighResTimeStamp maximumLatency; undefined resetLatency(); [Default] object toJSON(); };
This value is measured in milliseconds and is incremented each time a fallback frame is played by the output device at the end of the playout path. This metric can be used together with {{AudioPlayoutStats/totalFramesDuration}} to calculate the percentage of played out media that was not provided by the AudioContext.
This measures the number of synthesized fallback frames events. This counter increases every time a fallback frame is played after a non-fallback frame. That is, multiple consecutive fallback frames will increase {{AudioPlayoutStats/fallbackFramesDuration}} multiple times but is a single fallback frames event.
This attribute is the total duration, in milliseconds, of all audio frames that have been played by the audio device. Includes both fallback and non-fallback frames.
This is the average latency for the frames played since the last call to {{AudioPlayoutStats/resetLatency()}}, or since the creation of the AudioContext if {{AudioPlayoutStats/resetLatency()}} has not been called.
This measures the minimum latency for the frames played since the last call to {{AudioPlayoutStats/resetLatency()}}, or since the creation of the AudioContext if {{AudioPlayoutStats/resetLatency()}} has not been called.
This measures the maximum latency for the frames played since the last call to {{AudioPlayoutStats/resetLatency()}}, or since the creation of the AudioContext if {{AudioPlayoutStats/resetLatency()}} has not been called.
This method resets the latency counters. Note that it does not remove latency information that has accrued but not yet been exposed through the API.
var oldTotalFramesDuration = audioContext.playoutStats.totalFramesDuration; var oldFallbackFramesDuration = audioContext.playoutStats.fallbackFramesDuration; var oldFallbackFramesEvents = audioContext.playoutStats.fallbackFramesEvents; audioContext.playoutStats.resetLatency(); // Wait while playing audio ... // the number of seconds that were covered by the frames played by the output device between the two executions. let deltaTotalFramesDuration = (audioContext.playoutStats.totalFramesDuration - oldTotalFramesDuration) / 1000; let deltaFallbackFramesDuration = (audioContext.playoutStats.fallbackFramesDuration - oldFallbackFramesDuration) / 1000; let deltaFallbackFramesEvents = audioContext.playoutStats.fallbackFramesEvents - oldFallbackFramesEvents; // fallback frames fraction stat over the last deltaTotalFramesDuration seconds let fallbackFramesFraction = deltaFallbackFramesDuration / deltaTotalFramesDuration; // fallback event frequency stat over the last deltaTotalFramesDuration seconds let fallbackEventFrequency = deltaFallbackFramesEvents / deltaTotalFramesDuration; // Average playout delay stat during the last deltaTotalFramesDuration seconds let playoutDelay = audioContext.playoutStats.averageLatency / 1000;