You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -1533,6 +1536,10 @@ and to allow it only when the {{AudioContext}}'s [=relevant global object=] has
1533
1536
::
1534
1537
An ordered list to store pending {{Promise}}s created by
1535
1538
{{AudioContext/resume()}}. It is initially empty.
1539
+
1540
+
: <dfn>[[playout stats]]</dfn>
1541
+
::
1542
+
A slot where an instance of {{AudioPlayoutStats}} can be stored. It is initially null.
1536
1543
</dl>
1537
1544
1538
1545
<h4 id="AudioContext-constructors">
@@ -1769,6 +1776,19 @@ Attributes</h4>
1769
1776
the context is {{AudioContextState/running}}.
1770
1777
* When the operating system reports an audio device malfunction.
1771
1778
1779
+
: <dfn>playoutStats</dfn>
1780
+
::
1781
+
An instance of {{AudioPlayoutStats}} for this {{AudioContext}}.
1782
+
1783
+
<div algorithm="access playoutStats">
1784
+
<span class="synchronous">When accessing this attribute, run the following steps:</span>
1785
+
1786
+
1. If the {{[[playout stats]]}} slot is null, construct a new {{AudioPlayoutStats}} object with [=this=] as the argument, and store it in {{[[playout stats]]}}.
1787
+
1788
+
1. Return the value of the {{[[playout stats]]}} internal slot.
The {{AudioContext}} that this instance of {{AudioPlayoutStats}} is associated with.
11608
+
11609
+
: <dfn>[[underrun duration]]</dfn>
11610
+
::
11611
+
The total duration in seconds of [=underrun frames=] that {{[[audio context]]}} has played as of the last stat update, a double. Initialized to 0.
11612
+
11613
+
: <dfn>[[underrun events]]</dfn>
11614
+
::
11615
+
The total number of [=underrun events=] that has occurred in playout by {{[[audio context]]}} as of the last stat update, an int. Initialized to 0.
11616
+
11617
+
: <dfn>[[total duration]]</dfn>
11618
+
::
11619
+
The total duration in seconds of all frames (including [=underrun frames=]) that {{[[audio context]]}} has played as of the last stat update, a double. Initialized to 0.
11620
+
11621
+
: <dfn>[[average latency]]</dfn>
11622
+
::
11623
+
The average playout latency in seconds of frames played by {{[[audio context]]}} over the currently tracked interval, a double. Initialized to 0.
11624
+
11625
+
: <dfn>[[minimum latency]]</dfn>
11626
+
::
11627
+
The minimum playout latency in seconds of frames played by {{[[audio context]]}} over the currently tracked interval, a double. Initialized to 0.
11628
+
11629
+
: <dfn>[[maximum latency]]</dfn>
11630
+
::
11631
+
The maximum playout latency in seconds of frames played by {{[[audio context]]}} over the currently tracked interval, a double. Initialized to 0.
11632
+
11633
+
: <dfn>[[latency reset time]]</dfn>
11634
+
::
11635
+
The time when the latency statistics were last reset, a {{DOMHighResTimeStamp}}.
context: The {{AudioContext}} this new {{AudioPlayoutStats}} will be associated with.
11650
+
</pre>
11651
+
</dl>
11652
+
11653
+
<h4 id="AudioPlayoutStats-attributes">
11654
+
Attributes</h4>
11655
+
11656
+
Note: These attributes update only once per second and under specific conditions. See the <a href="#update-audio-stats">update audio stats</a> algorithm and <a href="#AudioPlayoutStats-mitigations">privacy mitigations</a> for details.
Once per second, execute the <a href="#update-audio-stats">update audio stats</a> algorithm:
11727
+
1. If {{[[audio context]]}} is not running, abort these steps.
11728
+
1. Let <var>canUpdate</var> be false.
11729
+
1. Let <var>document</var> be the current [=this=]'s [=relevant global object=]'s [=associated Document=].
11730
+
If <var>document</var> is [=Document/fully active=] and <var>document</var>'s [=Document/visibility state=] is `"visible"`, set <var>canUpdate</var> to true.
11731
+
1. Let <var>permission</var> be the [=permission state=] for the permission associated with [="microphone"=] access.
11732
+
If <var>permission</var> is "granted", set <var>canUpdate</var> to true.
11733
+
1. If <var>canUpdate</var> is false, abort these steps.
11734
+
1. Set {{[[underrun duration]]}} to the total duration of all [=underrun frames=] (in seconds) that
11735
+
{{[[audio context]]}} has played since its construction.
11736
+
1. Set {{[[underrun events]]}} to the number of times that {{[[audio context]]}}
11737
+
has played an [=underrun frame=] after a non-underrun frame since its construction.
11738
+
1. Set {{[[total duration]]}} to the total duration of all frames (in seconds) that
11739
+
{{[[audio context]]}} has played since its construction.
11740
+
1. Set {{[[average latency]]}} to the average playout latency (in seconds) of frames that
11741
+
{{[[audio context]]}} has played since {{[[latency reset time]]}}.
11742
+
1. Set {{[[minimum latency]]}} to the minimum playout latency (in seconds) of frames that
11743
+
{{[[audio context]]}} has played since {{[[latency reset time]]}}.
11744
+
1. Set {{[[maximum latency]]}} to the maximum playout latency (in seconds) of frames that
11745
+
{{[[audio context]]}} has played since {{[[latency reset time]]}}.
11746
+
</div>
11747
+
11748
+
<h4>Privacy considerations of glitch stats</h4>
11749
+
11750
+
<h5>Risk</h5>
11751
+
Audio underrun information could be used to form a cross-site
11752
+
covert channel between two cooperating sites.
11753
+
One site could transmit information by intentionally causing audio glitches
11754
+
(by causing very high CPU usage, for example) while the other site
To inihibit the usage of such a covert channel, the API implements these mitigations.
11758
+
- The values returned by the API should not be updated more than once per second.
11759
+
- The api should be restricted to sites fulfill at least one of the following criteria:
11760
+
1. The site has obtained <a href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia">getUserMedia</a> permission.
11761
+
11762
+
Note: The reasoning is that if a site has obtained <a href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia">getUserMedia</a> permission, it can receive glitch information or communicate efficiently through use of the microphone, making access to the information provided by {{AudioPlayoutStats}} redundant. These options include detecting glitches through gaps in the microphone signal, or communicating using human-inaudible sine waves. If microphone access is ever made safer in this regard, this condition should be reconsidered.
11763
+
1. The document is [=Document/fully active=] and its [=Document/visibility state=] is `"visible"`.
11764
+
11765
+
Note: Assuming that neither cooperating site has microphone permission, this criteria ensures that the site that receives the covert signal must be visible, restricting the conditions under which the covert channel can be used. It makes it impossible for sites to communicate with each other using the covert channel while not visible.
11766
+
11767
+
<h4>Usage example</h4>
11768
+
This example shows how the {{AudioPlayoutStats}} can be used to calculate audio underrun and latency statistics,
11769
+
and what the statistics might be used for.
11770
+
<pre line-numbers class="example" highlight="js">
11771
+
var oldTotalDuration = audioContext.playoutStats.totalDuration;
11772
+
var oldUnderrunDuration = audioContext.playoutStats.underrunDuration;
11773
+
var oldUnderrunEvents = audioContext.playoutStats.underrunEvents;
11774
+
audioContext.playoutStats.resetLatency();
11775
+
11776
+
// Wait while playing audio
11777
+
...
11778
+
11779
+
// the number of seconds that were covered by the frames played by the output device between the two executions.
11780
+
let deltaTotalDuration = audioContext.playoutStats.totalDuration - oldTotalDuration;
11781
+
let deltaUnderrunDuration = audioContext.playoutStats.underrunDuration - oldUnderrunDuration;
11782
+
let deltaUnderrunEvents = audioContext.playoutStats.underrunEvents - oldUnderrunEvents;
11783
+
11784
+
// underrun fraction stat over the last deltaTotalDuration seconds
11785
+
let underrunFraction = deltaUnderrunDuration / deltaTotalDuration;
11786
+
// underrun frequency stat over the last deltaTotalDuration seconds
11787
+
let underrunFrequency = deltaUnderrunEvents / deltaTotalDuration;
11788
+
// Average playout delay stat during the last deltaTotalDuration seconds
11789
+
let playoutDelay = audioContext.playoutStats.averageLatency;
11790
+
11791
+
if (underrunFrequency > 0) {
11792
+
// Do something to prevent audio glitches, like lowering WebAudio graph complexity
11793
+
}
11794
+
if (playoutDelay > 0.2) {
11795
+
// Do something to reduce latency, like suggesting alternative playout methods
0 commit comments