Skip to content

Commit 22637b1

Browse files
Remove boolean flag from interrupted state explainer (#883)
* Use link aliases to make reading easier * Remove mentions to the internal flag
1 parent e12f73f commit 22637b1

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

AudioContextInterruptedState/explainer.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@
1010

1111
## Introduction
1212

13-
The [Web Audio API](https://webaudio.github.io/web-audio-api/) is widely used to add advanced audio capabilities to web applications, like web-based games and music applications. One of the API's features is the [AudioContext interface](https://webaudio.github.io/web-audio-api/#AudioContext), which represents an audio graph. An `AudioContext` can find itself in one of three states: [`"suspended"`](https://webaudio.github.io/web-audio-api/#dom-audiocontextstate-suspended), [`"running"`](https://webaudio.github.io/web-audio-api/#dom-audiocontextstate-running), or [`"closed"`](https://webaudio.github.io/web-audio-api/#dom-audiocontextstate-closed). Once an `AudioContext` is in the `"running"` state, it can only pause media playback by transitioning to the `"suspended"` state when, and only when, user code calls [`suspend()`](https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspend) on this `AudioContext`. However, there are situations where we might want to let the User Agent (UA) decide when to interrupt playback - e.g., the proposed [`"media-playback-while-not-visible"`](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/IframeMediaPause/iframe_media_pausing.md) permission policy, the proposed [Audio Session API](https://w3c.github.io/audio-session/), or during a phone call where the calling application will need exclusive access to the audio hardware. To support these scenarios, we propose adding a new `"interrupted"` state to the [`AudioContextState`](https://webaudio.github.io/web-audio-api/#enumdef-audiocontextstate) enum.
13+
The [Web Audio API] is widely used to add advanced audio capabilities to web applications, like web-based games and music applications. One of the API's features is the [AudioContext ] interface, which represents an audio graph. An `AudioContext` can find itself in one of three states: [`"suspended"`], [`"running"`], or [`"closed"`]. Once an `AudioContext` is in the `"running"` state, it can only pause media playback by transitioning to the `"suspended"` state when, and only when, user code calls [`AudioContext.suspend()`] on this `AudioContext`. However, there are situations where we might want to let the User Agent (UA) decide when to interrupt playback - e.g., the proposed [`"media-playback-while-not-visible"` permission policy], the proposed [Audio Session API], or during a phone call where the calling application will need exclusive access to the audio hardware. To support these scenarios, we propose adding a new `"interrupted"` state to the [`AudioContextState`] enum.
1414

1515
## Goals
1616

1717
The main goal of this proposal is to allow the UA to be able to interrupt `AudioContext` playback when needed, given that there are a couple of user scenarios - e.g., incoming phone calls, screen lock, etc - and proposed web API's that could make good use of this functionality.
1818

1919
### "media-playback-while-not-visible" permission policy
2020

21-
The ["media-playback-while-not-visible" permission policy](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/IframeMediaPause/iframe_media_pausing.md) allows the UA to pause media playback on unrendered iframes. However, since the Web Audio API [does not allow the UA to suspend](https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspended-by-user-slot) audio playback, the proposed permission policy has no mechanism available to pause media playback.
21+
The [`"media-playback-while-not-visible"` permission policy] allows the UA to pause media playback on unrendered iframes. However, since the [Web Audio API does not allow the UA to suspend audio playback][audiocontext-suspended-by-user-slot], the proposed permission policy has no mechanism available to pause media playback.
2222

2323
### Audio Session API
2424

25-
Similarly, the [Audio Session API](https://w3c.github.io/audio-session/) could also make use of the `"interrupted"` state. Whenever the [`AudioSessionState`](https://w3c.github.io/audio-session/#enumdef-audiosessionstate) is `"interrupted"`, the AudioContext of the document would also transition to the `"interrupted"` state. As a matter of fact, the `AudioContext`'s `"interrupted"` state has been [implemented on WebKit](https://github.com/WebKit/WebKit/blob/1e8ea6e4777297ce82e6c911caa7cce2cc32e6a9/Source/WebCore/Modules/webaudio/AudioContextState.idl) and is currently being used by the Audio Session API.
25+
Similarly, the [Audio Session API] could also make use of the `"interrupted"` state. Whenever the [`AudioSessionState`] is `"interrupted"`, the AudioContext of the document would also transition to the `"interrupted"` state. As a matter of fact, the `AudioContext`'s `"interrupted"` state has been [implemented on WebKit](https://github.com/WebKit/WebKit/blob/1e8ea6e4777297ce82e6c911caa7cce2cc32e6a9/Source/WebCore/Modules/webaudio/AudioContextState.idl) and is currently being used by the Audio Session API.
2626

2727
In Safari, on MacOS Sonoma 14.5, if there an active web page with the `AudioContext` in the `"running"` state, and if we set the audio session type to `"auto"` with `navigator.audioSession.type = "auto"`; whenever the laptop's screen is locked, the AudioContext will transition to the `"interrupted"` state. When the screen is unlocked, the state will automatically switch to `"running"` again.
2828

@@ -43,21 +43,21 @@ enum AudioContextState {
4343
};
4444
```
4545

46-
Whenever an `AudioContext` transitions to either `"suspended"` or `"interrupted"`, audio playback would halt. The main difference between `"suspended"` and `"interrupted"` is that an `AudioContext` can only move to the `"suspended"` state if the [user triggered](https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspended-by-user-slot) the state change; while the UA can transition the context to the `"interrupted"` state if there is a need for that.
46+
Whenever an `AudioContext` transitions to either `"suspended"` or `"interrupted"`, audio playback would halt. The main difference between `"suspended"` and `"interrupted"` is that an `AudioContext` can only move to the `"suspended"` state if the [user triggered][audiocontext-suspended-by-user-slot] the state change; while the UA can transition the context to the `"interrupted"` state if there is a need for that.
4747

4848
With the addition of the `"interrupted"` state, the following state transitions would also be introduced:
4949
- `"running"` -> `"interrupted"`;
5050
- Would happen whenever the UA needs to interrupt audio playback.
5151
- `"suspended"` -> `"interrupted"`;
52-
- Shouldn't happen automatically. This transition should happen only if there is an ongoing interruption and [`AudioContext.resume()`](https://webaudio.github.io/web-audio-api/#dom-audiocontext-resume) is called.
52+
- Shouldn't happen automatically. This transition should happen only if there is an ongoing interruption and [`AudioContext.resume()`] is called.
5353
- `"interrupted"` -> `"running"`;
5454
- By the time that the cause of the interruption ceases to exist, the UA can transition to `"running"` if audio playback is allowed to resume automatically.
5555
- `"interrupted"` -> `"suspended"`; and
56-
- By the time that the cause of the interruption ceases to exist, the UA can transition to `"suspended"` if audio playback is **not** allowed to resume automatically or if [`AudioContext.suspend()`](https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspend) has been called during the interruption.
56+
- By the time that the cause of the interruption ceases to exist, the UA can transition to `"suspended"` if audio playback is **not** allowed to resume automatically or if [`AudioContext.suspend()`] has been called during the interruption.
5757
- `"interrupted"` -> `"closed"`.
5858
- The `AudioContext`'s state should move immediately to `"closed"` when `AudioContext.close()` is called.
5959

60-
The state transition from `"suspended"` to `"interrupted"` should not happen automatically, due to privacy concerns. Doing this transition automatically every time an interruption occurs might unnecessarily expose too much information to web pages - e.g., when a phone call comes in. To prevent fingerprinting in this scenario, an internal boolean flag, let's say `"is_interrupted"`, should be set and the AudioContext should remain in the `"suspended"` state, even though it is interrupted behind the curtains. However, calling [`AudioContext.resume()`](https://webaudio.github.io/web-audio-api/#dom-audiocontext-resume) should trigger the state change from `"suspended"` to `"interrupted"` if the interruption is still active. Therefore, while in the `"suspended"` state with an ongoing interruption:
60+
The state transition from `"suspended"` to `"interrupted"` should not happen automatically, due to privacy concerns. Doing this transition automatically every time an interruption occurs might unnecessarily expose too much information to web pages - e.g., when a phone call comes in. To prevent fingerprinting in this scenario, the AudioContext should remain in the `"suspended"` state, even though it is interrupted behind the curtains. However, calling [`AudioContext.resume()`] should trigger the state change from `"suspended"` to `"interrupted"` if the interruption is still active. Therefore, while in the `"suspended"` state with an ongoing interruption:
6161
- Calling `AudioContext.resume()` would return a rejected promise and transition to the `"interrupted"` state;
6262
- Calling `AudioContext.suspend()` is a NOOP;
6363

@@ -68,7 +68,7 @@ Finally, while in the `"interrupted"` state:
6868

6969
## Key scenarios
7070

71-
The `"interrupted"` state can be used by a couple of proposed API's, like the [`"media-playback-while-not-visible"`](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/IframeMediaPause/iframe_media_pausing.md) permission policy and the [Audio Session API](https://w3c.github.io/audio-session/) (this list is not exhaustive).
71+
The `"interrupted"` state can be used by a couple of proposed API's, like the [`"media-playback-while-not-visible"` permission policy] and the [Audio Session API] (this list is not exhaustive).
7272

7373
### "media-playback-while-not-visible" permission policy
7474

@@ -143,7 +143,7 @@ In the example below, we should have the following behavior:
143143

144144
### Audio Session API
145145

146-
Whenever the Audio Session API needs to pause media playback, the document's active AudioContext would transition to the `"interrupted"` state. Let's say that a UA decides that the Web Audio API should not play any audio whenever the screen gets locked and the navigator's object [`AudioSessionType`](https://w3c.github.io/audio-session/#enumdef-audiosessiontype) is set to `"auto"`. Since the current Web Audio API spec does not allow the UA to transition the `AudioContext`'s state to `"suspended"`, the UA can instead move the `AudioContext` to the `"interrupted"` state. Once the interruption ends, if the UA does not resume playback automatically, the application code can monitor the `AudioContext`'s state changes and be able to call `AudioContext.resume()` when the `AudioContext` is in the `"suspended"` state.
146+
Whenever the Audio Session API needs to pause media playback, the document's active AudioContext would transition to the `"interrupted"` state. Let's say that a UA decides that the Web Audio API should not play any audio whenever the screen gets locked and the navigator's object [`AudioSessionType`] is set to `"auto"`. Since the current Web Audio API spec does not allow the UA to transition the `AudioContext`'s state to `"suspended"`, the UA can instead move the `AudioContext` to the `"interrupted"` state. Once the interruption ends, if the UA does not resume playback automatically, the application code can monitor the `AudioContext`'s state changes and be able to call `AudioContext.resume()` when the `AudioContext` is in the `"suspended"` state.
147147

148148
Given the snippet below, where the `AudioSession` type is set to `"auto"`, we would have the following behavior:
149149
1. Page is loaded and the AudioContext is `"suspended"`.
@@ -186,15 +186,15 @@ When `AudioContext.resume()` is called for an `AudioContext` in the `"closed"` s
186186

187187
## Privacy considerations
188188

189-
Moving the `AudioContexts` to the `"interrupted"` state might giveaway some information about the user's behavior - for example, when the user started a voice call or locked the screen. However, since "interrupting" an `AudioContext` could be associated with several types of interruptions, exposing this new state shouldn't be a major concern. Moreover, to mitigate privacy concerns, this proposal forbids automatically transitioning from `"suspended"` to `"interrupted"` to avoid unnecessarily exposing interruptions. This state transition will only happen if [`AudioContext.resume()`](https://webaudio.github.io/web-audio-api/#dom-audiocontext-resume) is called.
189+
Moving the `AudioContexts` to the `"interrupted"` state might giveaway some information about the user's behavior - for example, when the user started a voice call or locked the screen. However, since "interrupting" an `AudioContext` could be associated with several types of interruptions, exposing this new state shouldn't be a major concern. Moreover, to mitigate privacy concerns, this proposal forbids automatically transitioning from `"suspended"` to `"interrupted"` to avoid unnecessarily exposing interruptions. This state transition will only happen if [`AudioContext.resume()`] is called.
190190

191191
## Considered alternatives
192192

193193
This sections lists a number of alternatives taken into consideration prior to and during the writing of this document.
194194

195195
### Re-use the `"suspended"` state
196196

197-
We first considered in the [`"media-playback-while-not-visible"`](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/IframeMediaPause/iframe_media_pausing.md) permission policy proposal using the `"suspended"` state whenever media playback needed to be paused. However, this is not possible, because [only user code can suspend](https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspended-by-user-slot) an `AudioContext`.
197+
We first considered in the [`"media-playback-while-not-visible"` permission policy] proposal using the `"suspended"` state whenever media playback needed to be paused. However, this is not possible, because [only user code can suspend][audiocontext-suspended-by-user-slot] an `AudioContext`.
198198

199199
## Stakeholder Feedback / Opposition
200200

@@ -211,4 +211,18 @@ We first considered in the [`"media-playback-while-not-visible"`](https://github
211211
Many thanks for valuable feedback and advice from:
212212
- [Erik Anderson](https://github.com/erik-anderson)
213213
- [Rahul Singh](https://github.com/rahulsingh-msft)
214-
- [Sunggook Chue](https://github.com/sunggook)
214+
- [Sunggook Chue](https://github.com/sunggook)
215+
216+
[AudioContext]: https://webaudio.github.io/web-audio-api/#AudioContext
217+
[`AudioContextState`]: https://webaudio.github.io/web-audio-api/#enumdef-audiocontextstate
218+
[`AudioContext.resume()`]: https://webaudio.github.io/web-audio-api/#dom-audiocontext-resume
219+
[`AudioContext.suspend()`]: https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspend
220+
[`AudioSessionState`]: https://w3c.github.io/audio-session/#enumdef-audiosessionstate
221+
[`AudioSessionType`]: https://w3c.github.io/audio-session/#enumdef-audiosessiontype
222+
[Audio Session API]: https://w3c.github.io/audio-session/
223+
[`"closed"`]: https://webaudio.github.io/web-audio-api/#dom-audiocontextstate-closed
224+
[`"media-playback-while-not-visible"` permission policy]: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/IframeMediaPause/iframe_media_pausing.md
225+
[`"running"`]: https://webaudio.github.io/web-audio-api/#dom-audiocontextstate-running
226+
[`"suspended"`]: https://webaudio.github.io/web-audio-api/#dom-audiocontextstate-suspended
227+
[audiocontext-suspended-by-user-slot]: https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspended-by-user-slot
228+
[Web Audio API]: https://webaudio.github.io/web-audio-api/

0 commit comments

Comments
 (0)