Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AudioContext "interrupted" state #2611

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 94 additions & 11 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,8 @@ for="BaseAudioContext">[[control thread state]]</dfn> that take values from
enum AudioContextState {
"suspended",
"running",
"closed"
"closed",
"interrupted"
};
</pre>

Expand Down Expand Up @@ -745,6 +746,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 @@ -1965,26 +1972,39 @@ Methods</h4>

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. Let <var>promise</var> be a new Promise.

2. If the {{[[control thread state]]}} on the
3. 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>.
4. Set {{[[suspended by user]]}} to <code>false</code>.

5. If the {{[[control thread state]]}} on the
{{AudioContext}} is <code>suspended</code> and there is an ongoing [=interruption=]:

4. If the context is not <a>allowed to start</a>, append
1. Queue a media element task</a> to execute the following steps:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Queue a media element task</a> to execute the following steps:
1. <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:

Some parts of the spec use [=Queue a media element task=] instead. But I don't know which one is preferable. Maybe it depends on the context.


1. Set the {{BaseAudioContext/state}} attribute of the {{AudioContext}} to "{{AudioContextState/interrupted}}".

2. [=Queue a media element task=] to [=fire an event=] named
{{BaseAudioContext/statechange}} at the {{AudioContext}}.

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

6. 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>.

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

6. <a>Queue a control message</a> to resume the {{AudioContext}}.
8. <a>Queue a control message</a> to resume the {{AudioContext}}.

7. Return <var>promise</var>.
9. Return <var>promise</var>.
</div>

<div id="context-resume" algorithm="run a control message in AudioContext">
Expand Down Expand Up @@ -4196,7 +4216,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 @@ -11662,7 +11682,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 @@ -11769,7 +11789,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 @@ -12089,6 +12109,69 @@ 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. This could happen when there is an incoming
call from a VoIP application.

The {{AudioContext}} |audioContext| performs the following steps on the <a>rendering thread</a> when an interruption happens.

1. If the |audioContext|'s {{[[rendering thread state]]}} is <code>closed</code> or <code>interrupted</code>:

1. Abort these steps.

1. If the |audioContext|'s {{[[rendering thread state]]}} is <code>running</code>:

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

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

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

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

1. If the |audioContext|'s {{[[rendering thread state]]}} is <code>suspended</code>:

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

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

1. Set the |audioContext|'s {{[[rendering thread state]]}} to <code>interrupted</code>.

Note: If the {{AudioContext}} is <code>suspended</code> 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.

The {{AudioContext}} |audioContext| performs the following steps on the <a>rendering thread</a> when the [=interruption=] ends.

1. If the |audioContext|'s {{[[rendering thread state]]}} is not <code>interrupted</code>:

1. Abort these steps.

1. If the |audioContext|'s {{[[rendering thread state]]}} was <code>running</code> before the [=interruption=] or if the the |audioContext|'s {{[[rendering thread state]]}} was <code>suspended</code> and {{AudioContext/resume}} was called during the [=interruption=]:

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

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

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

4. [=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 |audioContext|'s {{[[control thread state]]}} to <code>running</code>.

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

1. If the |audioContext|'s {{[[rendering thread state]]}} was <code>suspended</code> before the [=interruption=]:

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

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

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

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

Expand Down