This document defines a set of JavaScript APIs that let a Web application manage how audio is rendered on the user audio output devices.
The WebRTC and Device and Sensors Working Group intend to publish this specification as a Candidate Recommendation soon. Consequently, this is a Request for wide review of this document.
This proposal allows JavaScript to direct the audio output of a media element to permitted devices other than the system or user agent default. This can be helpful in a variety of real-time communication scenarios as well as general media applications. For example, an application can use this API to programmatically direct output to a device such as a Bluetooth headset or speakerphone.
HTMLMediaElement
ExtensionsThis section specifies additions to the
HTMLMediaElement
[[!HTML5]] when the Audio Output Devices API is
supported.
When the HTMLMediaElement
constructor is invoked, the user
agent MUST add the following initializing step:
Let the element have a [[\SinkId]] internal slot,
initialized to ""
.
partial interface HTMLMediaElement { [SecureContext] readonly attribute DOMString sinkId; [SecureContext] Promise<void> setSinkId (DOMString sinkId); };
sinkId
of type DOMString, readonlyThis attribute contains the ID of the audio device through which
output is being delivered, or the empty string if output is
delivered through the user-agent default device. If nonempty, this
ID should be equal to the
deviceId
attribute of one of the
MediaDeviceInfo
values returned from
MediaDevices.enumerateDevices()
[[!GETUSERMEDIA]].
On getting, the attribute MUST return the value of the [[\SinkId]] slot.
setSinkId
Sets the ID of the audio device through which audio output should be rendered if the application is permitted to play out of a given device.
When this method is invoked, the user agent must run the following steps:
Let element be the HTMLMediaElement
object on which this method was invoked.
Let sinkId be the method's first argument.
If sinkId is equal to element's
[[\SinkId]],
return a promise resolved with undefined
.
Let p be a new promise.
Run the following substeps in parallel:
If sinkId does not match any audio output
device identified by the result that would be provided by
enumerateDevices()
, reject
p with a new
DOMException
whose name is
NotFoundError
and abort these substeps.
If the application is not permitted to play audio through the
device identified by sinkId, reject p
with a new
DOMException
whose name is
NotAllowedError
and abort these substeps.
Switch the underlying audio output device for element to the audio device identified by sinkId.
If this substep is successful and the media
element's
paused
attribute is false, audio MUST stop playing
out of the device represented by the element's sinkId
attribute and will start
playing out of the device identified by sinkId
If the preceding substep failed, reject p
with a new DOMException
whose name is
AbortError
and abort these substeps.
Queue a task that runs the following steps:
Set element's [[\SinkId]] to sinkId.
Resolve p.
Return p.
New audio devices may become available to the user agent, or an
audio device (identified by a media element's sinkId
attribute) that had
previously become unavailable may become available
again, for example, if it is unplugged and later plugged back in.
In this scenario, the user agent must run the following steps:
Let sinkId be the identifier for the newly available device.
For each media element whose sinkId
attribute is equal to
sinkId:
The following paragraph is non-normative.
If the application wishes to react to the device
change, the application can listen to the
devicechange
event and query
enumerateDevices()
for the list of updated
devices.
This document extends the Web platform with the ability to direct audio output to non-default devices, when user permission is given. User permission is necessary because playing audio out of a non-default device may be unexpected behavior to the user, and may cause a nuisance. For example, suppose a user is in a library or other quiet public place where she is using a laptop with system audio directed to a USB headset. Her expectation is that the laptop’s audio is private and she will not disturb others. If any Web application can direct audio output through arbitrary output devices, a mischievous website may play loud audio out of the laptop’s external speakers without the user’s consent.
To prevent these kinds of nuisance scenarios, the user agent must acquire the user’s consent to access non-default audio output devices. This would prevent the library example outlined earlier, because the application would not be permitted to play out audio from the system speakers.
The specification adds no permission requirement to the default audio output device.
The user agent may explicitly obtain user consent to play audio out of non-default output devices; the details of this process are left to the implementation. For example, one approach could be to add an explicit user prompt of the form "example.com wants to access all your sound output devices".
However, implementations MUST support implicit consent via the
getUserMedia()
permission prompt; when an audio input
device is permitted and opened via
getUserMedia()
, this also permits access to any associated
audio output devices (i.e., those with the same
groupId
). This conveniently handles the common case of wanting
to route both input and output audio through a headset or speakerphone
device.
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)
Implementations that use ECMAScript to implement the APIs defined in this specification must implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]], as this specification uses that specification and terminology.
The following people have contributed directly to the development of this specification: Harald Alvestrand, Rick Byers, Dominique Hazael-Massieux (via the HTML5Apps project), Philip Jägenstedt, Victoria Kirst, Shijun Sun, Martin Thomson, Chris Wilson.