Skip to content
181 changes: 158 additions & 23 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -709,16 +709,19 @@ Each {{BaseAudioContext}} has a unique
media element event task source</a>.
Additionally, a {{BaseAudioContext}} has several private slots <dfn attribute
for="BaseAudioContext">[[rendering thread state]]</dfn> and <dfn attribute
for="BaseAudioContext">[[control thread state]]</dfn> that take values from
{{AudioContextState}}, and that are both initially set to <code>"suspended"
</code>, and a private slot <dfn attribute for="BaseAudioContext">
[[render quantum size]]</dfn> that is an unsigned integer.
for="BaseAudioContext">[[control thread state]]</dfn> that take values
from {{AudioContextState}}, and that are both initially set to <code>"suspended"
</code>, <dfn attribute for="BaseAudioContext">[[state before interruption]]
</dfn> that also take values from {{AudioContextState}} and is initially set to
`null` and a private slot <dfn attribute for="BaseAudioContext">[[render quantum
size]]</dfn> that is an unsigned integer.

<pre class="idl">
enum AudioContextState {
"suspended",
"running",
"closed"
"closed",
"interrupted"
};
</pre>

Expand Down Expand Up @@ -746,6 +749,12 @@ enum AudioContextState {
<td>
This context has been released, and can no longer be used to
process audio. All system audio resources have been released.
<tr>
<td>
"<dfn>interrupted</dfn>"
<td>
This context is currently interrupted and cannot process audio
until the [=interruption=] ends.
</table>
</div>

Expand Down Expand Up @@ -1542,6 +1551,8 @@ Constructors</h4>

1. Set a {{[[rendering thread state]]}} to <code>suspended</code> on
|context|.

1. Set {{[[state before interruption]]}} to `null` on |context|.

1. Let |messageChannel| be a new {{MessageChannel}}.

Expand Down Expand Up @@ -1960,28 +1971,50 @@ Methods</h4>
<span class="synchronous">When resume is called,
execute these steps:</span>

1. If [=this=]'s [=relevant global object=]'s [=associated Document=] is not [=fully active=] then return [=a promise rejected with=] "{{InvalidStateError}}" {{DOMException}}.
1. If [=this=]'s [=relevant global object=]'s
[=associated Document=] is not [=fully active=] then return
[=a promise rejected with=] "{{InvalidStateError}}"
{{DOMException}}.

1. Let <var>promise</var> be a new Promise.

2. If the {{[[control thread state]]}} on the
1. If the {{[[control thread state]]}} on the
{{AudioContext}} is <code>closed</code> reject the
promise with {{InvalidStateError}}, abort these steps,
returning <var>promise</var>.

3. Set {{[[suspended by user]]}} to <code>false</code>.
1. Set {{[[suspended by user]]}} to <code>false</code>.

1. If the context's {{BaseAudioContext/state}} attribute is
"{{AudioContextState/suspended}}" and the context's
{{[[control thread state]]}} is
"{{AudioContextState/interrupted}}", then:

4. If the context is not <a>allowed to start</a>, append
<var>promise</var> to {{BaseAudioContext/[[pending promises]]}} and
{{AudioContext/[[pending resume promises]]}} and abort these steps, returning
<var>promise</var>.
1. <a>Queue a media element task</a> to execute the following steps:

5. Set the {{[[control thread state]]}} on the
{{AudioContext}} to <code>running</code>.
1. Set the {{BaseAudioContext/state}} attribute of the
{{AudioContext}} to "{{AudioContextState/interrupted}}".

1. Set the {{[[state before interruption]]}} slot to
"{{AudioContextState/running}}".

6. <a>Queue a control message</a> to resume the {{AudioContext}} with <var>promise</var>.
1. [=Queue a media element task=] to [=fire an event=] named
{{BaseAudioContext/statechange}} at the {{AudioContext}}.

1. Reject the promise with {{InvalidStateError}}, abort these
steps, returning <var>promise</var>.

7. Return <var>promise</var>.
1. If the context is not <a>allowed to start</a>, append
<var>promise</var> to {{BaseAudioContext/[[pending promises]]}}
and {{AudioContext/[[pending resume promises]]}} and abort
these steps, returning <var>promise</var>.

1. Set the {{[[control thread state]]}} on the {{AudioContext}} to
<code>running</code>.

1. <a>Queue a control message</a> to resume the {{AudioContext}} with <var>promise</var>.

1. Return <var>promise</var>.
</div>

<div id="context-resume" algorithm="run a control message in AudioContext">
Expand Down Expand Up @@ -2080,14 +2113,19 @@ Methods</h4>

1. Attempt to <a>release system resources</a>.

2. Set the {{[[rendering thread state]]}} on the {{AudioContext}} to <code>suspended</code>.
1. If the {{[[rendering thread state]]}} on the {{AudioContext}} is
"{{AudioContextState/interrupted}}", <a>queue a media element
task</a> to set the {{[[state before interruption]]}} slot to
"{{AudioContextState/suspended}}".

3. <a href="https://html.spec.whatwg.org/multipage/media.html#queue-a-media-element-task">
queue a media element task</a> to execute the following steps:
1. Set the {{[[rendering thread state]]}} on the {{AudioContext}} to
"{{AudioContextState/suspended}}".

1. <a>Queue a media element task</a> to execute the following steps:

1. Resolve <var>promise</var>.

2. If the {{BaseAudioContext/state}}
1. If the {{BaseAudioContext/state}}
attribute of the {{AudioContext}} is not already "{{AudioContextState/suspended}}":

1. Set the {{BaseAudioContext/state}} attribute of the {{AudioContext}} to "{{AudioContextState/suspended}}".
Expand Down Expand Up @@ -4071,7 +4109,7 @@ Methods</h4>
scheduled parameter changes with times greater than or equal to
{{AudioParam/cancelAndHoldAtTime()/cancelTime!!argument}}. However, in addition, the automation
value that would have happened at {{AudioParam/cancelAndHoldAtTime()/cancelTime!!argument}} is
then proprogated for all future time until other automation
then propagated for all future time until other automation
events are introduced.

The behavior of the timeline in the face of
Expand Down Expand Up @@ -11534,7 +11572,7 @@ and a <a>rendering thread</a>.

The <dfn>control thread</dfn> is the thread from which the
{{AudioContext}} is instantiated, and from which authors
manipulate the audio graph, that is, from where the operation on a
manipulate the audio graph, that is, from where the operations on a
{{BaseAudioContext}} are invoked. The <dfn>rendering thread</dfn>
is the thread on which the actual audio output is computed, in
reaction to the calls from the <a>control thread</a>. It can be a
Expand Down Expand Up @@ -11641,7 +11679,7 @@ The algorithm for rendering a block of audio from a {{BaseAudioContext}}
in the algorithm of <a href="#rendering-a-graph">rendering a graph</a>.

The {{AudioContext}} <a>rendering thread</a> is driven by a
<dfn>system-level audio callback</dfn>, that is periodically
<dfn>system-level audio callback</dfn>, that is periodically called
at regular intevals. Each call has a <dfn>system-level audio callback buffer
size</dfn>, which is a varying number of sample-frames that needs to be
computed on time before the next <a>system-level audio callback</a> arrives.
Expand Down Expand Up @@ -11961,6 +11999,103 @@ running the algorithm for an {{AudioNode}}, using an <a>input
buffer</a> and the value(s) of the {{AudioParam}}(s) of this
{{AudioNode}} as the input for this algorithm.

<h3 id="interruption-handling">Handling an interruption on the {{AudioContext}}</h3>

An <dfn>interruption</dfn> is an event generated by the user agent when it needs
to halt audio playback for an {{AudioContext}}. For example, The user agent may
create an interruption when another application requests exclusive access to the
audio output hardware.

When an [=interruption=] happens, the user agent MUST <a>queue a control message</a>
to interrupt the {{AudioContext}}.

Running a <a>control message</a> to <dfn attribute for="AudioContext"
lt="interruption-start">interrupt an {{AudioContext}}</dfn> |context|
means running these steps on the <a>rendering thread</a>:

1. If the |context|'s {{[[rendering thread state]]}} is
{{AudioContextState/closed}} or {{AudioContextState/interrupted}}, abort
these steps.

1. If the |context|'s {{[[rendering thread state]]}} is
{{AudioContextState/running}}:

1. Attempt to <a>release system resources</a>.

1. [=Queue a media element task=] to execute the following steps:

1. Set the |context|'s {{[[control thread state]]}} to
{{AudioContextState/interrupted}}.

1. Set the |context|'s {{[[state before interruption]]}} slot to
"{{AudioContextState/running}}".

1. [=Fire an event=] named {{BaseAudioContext/statechange}} at the
|context|.

1. If the |context|'s {{[[rendering thread state]]}} is
{{AudioContextState/suspended}}:

1. [=Queue a media element task=] to execute the following steps:

1. Set the |context|'s {{[[control thread state]]}} to
{{AudioContextState/interrupted}}.

1. Set the |context|'s {{[[state before interruption]]}} slot to
"{{AudioContextState/suspended}}".

1. Set the |context|'s {{[[rendering thread state]]}} to
{{AudioContextState/interrupted}}.

Note: If the {{AudioContext}} is {{AudioContextState/suspended}} a
{{BaseAudioContext/statechange}} event is not fired for privacy reasons to avoid
over-sharing user activity - e.g. when a phone call comes in or when the screen
gets locked.

When an [=interruption=] ends, the user agent MUST <a>queue a control message</a>
to <dfn attribute for="AudioContext" lt="interruption-end">end the
{{AudioContext}} interruption</dfn>.

Running a <a>control message</a> to end an {{AudioContext}} |context|
[=interruption=] means running these steps on the <a>rendering thread</a>:

1. If the |context|'s {{[[rendering thread state]]}} is not
{{AudioContextState/interrupted}}, abort these steps.

1. If the |context|'s {{[[state before interruption]]}} is
"{{AudioContextState/running}}":

1. Attempt to <a href="#acquiring">acquire system resources</a>.

1. Set the {{[[rendering thread state]]}} on the {{AudioContext}} to
"{{AudioContextState/running}}".

1. Start <a href="#rendering-loop">rendering the audio graph</a>.

1. [=Queue a media element task=] to execute the following steps:

1. If the {{BaseAudioContext/state}} attribute of the {{AudioContext}}
is not already "{{AudioContextState/running}}":

1. Set the |context|'s {{[[control thread state]]}} to
"{{AudioContextState/running}}".

1. [=Fire an event=] named {{BaseAudioContext/statechange}} at the
|context|.

1. If the |context|'s {{[[state before interruption]]}} is
"{{AudioContextState/suspended}}"

1. Set the {{[[rendering thread state]]}} on the {{AudioContext}} to
<code>suspended</code>.

1. [=Queue a media element task=] to execute the following steps:

1. Set the |context|'s {{[[control thread state]]}} to
<code>suspended</code>.

1. Set the |context|'s {{[[state before interruption]]}} to `null`.

<h3 id="error-handling-on-a-running-audio-context">
Handling an error from System Audio Resources on the {{AudioContext}}</h3>

Expand Down
Loading