This document defines how a user's display, or parts thereof, can be used as the source of a media stream using getDisplayMedia, an extension to the Media Capture API [[!GETUSERMEDIA]].

This document is not complete. It is subject to major changes and, while early experimentations are encouraged, it is therefore not intended for implementation.

Introduction

This document describes an extension to the Media Capture API [[GETUSERMEDIA]] that enables the acquisition of a user's display, or part thereof, in the form of a video stream. This enables a number of applications, including screen sharing using WebRTC [[WEBRTC]].

This feature has signficant security implications. Applications that use this API to access information that is displayed to users could access confidential information from other origins if that information is under the control of the application. This includes content that would otherwise be inaccessible due to the protections offered by the user agent sandbox.

This document concerns itself primarily with the capture of video, but the general mechanisms defined here could be extended to other types of media, of which audio [[GETUSERMEDIA]] and depth [[MEDIACAPTURE-DEPTH]] are currently defined.

This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.

Implementations that use ECMAScript [[ECMA-262]] 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.

Example

The following example demonstrates a request for display capture using the navigator.mediaDevices.getDisplayMedia method defined in this document.

try {
  let mediaStream = await navigator.mediaDevices.getDisplayMedia({video:true});
  videoElement.srcObject = mediaStream;
} catch (e) {
  console.log('Unable to acquire screen capture: ' + e);
}

Terminology

This document uses the definition of MediaStreamTrack, and ConstrainablePattern from [[!GETUSERMEDIA]].

Screen capture encompasses the capture of several different types of screen-based surfaces. Collectively, these are referred to as display surfaces, of which this document defines the following types:

This document draws a distinction between two variants of each type of display surface:

Some operating systems permit windows from different applications to occlude other windows, in whole or part, so the visible display surface is a strict subset of the logical display surface.

The source pixel ratio of a display surface is 1/96th of 1 inch divided by its vertical pixel size.

The terms permission, retrieve the permission state, prompt the user to choose, and create a permission storage entry are defined in [[!permissions]].

The devicechange event is defined in [[GETUSERMEDIA]] Section 9.2, the MediaTrackSupportedConstraints dictionary is defined in [[GETUSERMEDIA]] Section 4.3.4, the MediaTrackConstraintSet dictionary is defined in [[GETUSERMEDIA]] Section 4.3.6, and the MediaTrackSettings dictionary is defined in [[GETUSERMEDIA]] Section 4.3.7.

Capturing Displayed Media

Capture of displayed media is enabled through the addition of a new getDisplayMedia method on the MediaDevices interface, that is similar to getUserMedia [[!GETUSERMEDIA]], except that it acquires media from one display device chosen by the end-user each time.

MediaDevices Additions

partial interface MediaDevices {
    Promise<MediaStream> getDisplayMedia (optional MediaStreamConstraints constraints);
};
getDisplayMedia

Prompts the user for permission to live-capture their display.

The user agent MUST let the end-user choose which display surface to share out of all available choices every time, and MUST NOT use constraints to limit that choice. Instead, constraints MUST be applied to the media chosen by the user, only after they have made their selection. This prevents an application from influencing the selection of sources, see for details.

In addition to drawing from a different set of sources and requiring user selection, getDisplayMedia also differs from getUserMedia in that "granted" permissions cannot be persisted.

When the getDisplayMedia() method is called, the User Agent MUST run the following steps:

  1. Let constraints be the method's first argument.

  2. For each member present in constraints whose value, value, is a dictionary, run the following steps:

    1. If value contains a member named advanced, return a promise rejected with a newly created TypeError.

    2. If value contains a member which in turn is a dictionary containing a member named either min or exact, return a promise rejected with a newly created TypeError.

  3. Let requestedMediaTypes be the set of media types in constraints with either a dictionary value or a value of true.

  4. If requestedMediaTypes is the empty set, set requestedMediaTypes to a set containing "video".

  5. If the current settings object's responsible document is NOT fully active, return a promise rejected with a DOMException object whose name attribute has the value InvalidStateError.

  6. Let p be a new promise.

  7. Run the following steps in parallel:

    1. For each media type T in requestedMediaTypes,

      1. If no sources of type T are available, reject p with a new DOMException object whose name attribute has the value NotFoundError.

      2. Retrieve the permission state for obtaining sources of type T in the current browsing context. If the permission state is "denied", jump to the step labeled PermissionFailure below.

    2. Optionally, e.g., based on a previously-established user preference, for security reasons, or due to platform limitations, jump to the step labeled Permission Failure below.

    3. Prompt the user to choose a display device, with a PermissionDescriptor named "display-capture", resulting in a set of provided media.

      The provided media MUST include precisely one track of each media type in requestedMediaTypes. The devices chosen MUST be the ones determined by the user. Once selected, the source of a MediaStreamTrack MUST NOT change.

      User Agents are encouraged to warn users against sharing browser display devices as well as monitor display devices where browser windows are visible, or otherwise try to discourage their selection on the basis that these represent a significantly higher risk when shared.

      If the result of the request is "granted", then for each device that is sourcing the provided media, using a stable and private id for the device, deviceId, set [[\devicesLiveMap]][deviceId] to true, if it isn’t already true, and set the [[\devicesAccessibleMap]][deviceId] to true, if it isn’t already true.

      The User Agent MUST NOT create a permission storage entry with a value of "granted".

      If the result is "denied", jump to the step labeled Permission Failure below. If the user never responds, this algorithm stalls on this step.

      If the user grants permission but a hardware error such as an OS/program/webpage lock prevents access, reject p with a new DOMException object whose name attribute has the value NotReadableError and abort these steps.

      If the result is "granted" but device access fails for any reason other than those listed above, reject p with a new DOMException object whose name attribute has the value AbortError and abort these steps.

    4. Let stream be the MediaStream object for which the user granted permission.

    5. Run the ApplyConstraints algorithm on all tracks in stream with the appropriate constraints. Should this fail, let failedConstraint be the result of the algorithm that failed, and let message be either undefined or an informative human-readable message, and then reject p with a new OverconstrainedError created by calling OverconstrainedError(failedConstraint, message).

    6. Resolve p with stream and abort these steps.

    7. Permission Failure: Reject p with a new DOMException object whose name attribute has the value NotAllowedError.

  8. Return p.

Closed and Minimized Display Surfaces

A display surface that is being shared may temporarily or permanently become inaccessible to the application because of actions taken by the operating system or user agent. What makes a display surface considered inaccesible is outside the scope of this specification, but examples MAY include a monitor disconnecting or an application, window or browser closing or becoming minimized.

When display surface enters an inaccessible state that is not necessarily permanent, the user agent MUST queue a task that sets the muted state of the corresponding media track to true.

When display surface exits an inaccessible state and becomes accessible, the user agent MUST queue a task that sets the muted state of the corresponding media track to false.

When a display surface enters an inaccessible state that is permanent (such as the source application terminating), the user agent MUST queue a task that ends the corresponding media track.

A stream that was just returned by getDisplayMedia MAY contain tracks that are muted by default. Audio and video tracks belonging to the same stream MAY be muted/unmuted independently of one another.

Unconstrained Display Surface Selection

Not accepting constraints for source selection means that getDisplayMedia only provides fingerprinting surface that exposes whether audio, video or audio and video display sources are present. (This is a fingerprinting vector.)

Constrainable Properties for Captured Display Surfaces

Constraints serve a different purpose in getDisplayMedia than they do in getUserMedia. They do not aid discovery, instead they are applied only after user-selection.

Some of these constraints enable user agent processing like downscaling and frame decimation, as well as display-specific features. Others enable observation of inherent properties of a user-selected display surface, as capabilities and settings.

The following new and existing MediaStreamTrack Constrainable Properties are defined to apply to the user-selected video display surface, with the following behavior:

Property Name Type Behavior
width ConstrainULong The width or width range, in pixels. As a capability, max MUST reflect the display surface's width, and min MUST reflect the width of the smallest aspect-preserving representation available through downscaling by the user agent.
height ConstrainULong The height or height range, in pixels. As a capability, max MUST reflect the display surface's height, and min MUST reflect the height of the smallest aspect-preserving representation available through downscaling by the user agent.
frameRate ConstrainDouble The frame rate (frames per second) or frame rate range. As a capability, max MUST reflect the display surface's frame rate, and min MUST reflect the lowest frame rate available through frame decimation by the user agent.
aspectRatio ConstrainDouble The exact aspect ratio (width in pixels divided by height in pixels, represented as a double rounded to the tenth decimal place) or aspect ratio range. As a setting, represents width / height. As a capability, min and max both MUST be the current setting value, rendering this property immutable from the application viewpoint.
resizeMode ConstrainDOMString This string (or each string, when a list) should be one of the members of VideoResizeModeEnum. As a setting, none means the MediaStreamTrack contains all bits needed to render the display in full detail, which if the source pixel ratio > 1, means width and height will be larger than the display's appearance from an end-user viewpoint would suggest, whereas crop-and-scale means the MediaStreamTrack contains an aspect-preserved representation of the display surface that has been downscaled by the user agent, but not cropped. As a capability, the values none and crop-and-scale both MUST be present.
displaySurface ConstrainDOMString This string (or each string, when a list) should be one of the members of DisplayCaptureSurfaceType. As a setting, indicates the type of display surface that is being captured. As a capability, the setting value MUST be the lone value present, rendering this property immutable from the application viewpoint.
logicalSurface ConstrainBoolean As a setting, a value of true indicates capture of a logical display surface, whereas a value of false indicates a capture capture of a visible display surface. As a capability, this same value MUST be the lone value present, rendering this property immutable from the application viewpoint.
cursor ConstrainDOMString This string (or each string, when a list) should be one of the members of CursorCaptureConstraint. As a setting, indicates if and when the cursor is included in the captured display surface. As a capability, the user agent MUST include only the set of values from CursorCaptureConstraint it is capable of supporting for this display surface.

When inherent properties of the underlying source of a user-selected display surface change, for example in response to the end-user resizing a captured window, and these changes render the capabilities and/or settings of one or more constrainable properties outdated, the user agent MUST queue a task to run the following step:

  1. Update all affected constrainable properties at the same time.

    If this causes an "overconstrained" situation, then the user agent MUST ignore the culprit constraints for as long as they overconstrain. The user agent MUST NOT mute the track, and the user agent MUST NOT fire the overconstrained event.

While min and exact constraints produce TypeError on getDisplayMedia(), this specification does not alter the track.applyConstraints() method. Therefore, they may instead produce OverconstrainedError or succeed depending on values, and therefore potentially be present to cause this "overconstrained" situation. The max constraint may also cause this, e.g. with aspectRatio. This spec considers these to be edge cases that aren't useful.

Downscaling and Frame Decimation

For the purposes of the SelectSettings algorithm, the user agent SHOULD consider all possible combinations of downscaled dimensions that preserve the aspect ratio of the original display surface (to the nearest pixel), and frame rates available through frame decimation, as available settings dictionaries.

The downscaling and decimation effects of constraints is then effectively governed by the fitness distance algorithm.

The intent is for the user agent to produce output that is close to the ideal width, ideal height, and/or ideal frameRate when these are specified, while at all times preserving the aspect ratio of the original display surface.

The user agent SHOULD downscale by the source pixel ratio by default, unless otherwise directed by applied constraints.

The user agent MUST NOT crop the captured output.

The user agent MUST NOT upscale the captured output, or create additional frames, except as needed to preserve high resolutions and frame rates in an aggregated display surface.

The max constraint type lets a web application provide a maximum envelope for constrainable properties like width and height. This is helpful to limit extreme aspect ratios, should the end-user resize a window or browser surface to such an extreme while it is being captured.

Extensions to MediaTrackSupportedConstraints

MediaTrackSupportedConstraints is extended here with the list of constraints that a User Agent recognizes.

partial dictionary MediaTrackSupportedConstraints {
             boolean displaySurface = true;
             boolean logicalSurface = true;
             boolean cursor = true;
};
displaySurface of type boolean, defaulting to true

Whether displaySurface constraint is recognized.

logicalSurface of type boolean, defaulting to true

Whether logicalSurface constraint is recognized.

cursor of type boolean, defaulting to true

Whether cursor constraint is recognized.

Extensions to MediaTrackConstraintSet

MediaTrackConstraintSet is used for reading the current status of constraints.

partial dictionary MediaTrackConstraintSet {
             ConstrainDOMString displaySurface;
             ConstrainBoolean   logicalSurface;
             ConstrainDOMString   cursor;
};
displaySurface of type ConstrainDOMString

The type of display surface that is being captured. This assumes values from the DisplayCaptureSurfaceType enumeration.

logicalSurface of type ConstrainBoolean

A value of true indicates capture of a logical display surface; a value of false indicates a capture capture of a visible display surface.

cursor of type ConstrainDOMString

Assumes values from the CursorCaptureConstraint enumeration that determines if and when the cursor is included in the captured display surface.

Extensions to MediaTrackSettings

When the getSettings() method is invoked on a video stream track, the user agent must return the extended MediaTrackSettings dictionary, representing the current status of the underlying user agent.

partial dictionary MediaTrackSettings {
             DOMString displaySurface;
             boolean   logicalSurface;
             DOMString   cursor;
};
displaySurface of type DOMString

The type of display surface that is being captured. This assumes values from the DisplayCaptureSurfaceType enumeration.

logicalSurface of type boolean

A value of true indicates capture of a logical display surface; a value of false indicates a capture capture of a visible display surface.

cursor of type DOMString

Assumes values from the CursorCaptureConstraint enumeration that determines if and when the cursor is included in the captured display surface.

DisplayCaptureSurfaceType

The DisplayCaptureSurfaceType enumeration describes the different types of display surface.

enum DisplayCaptureSurfaceType {
    "monitor",
    "window",
    "application",
    "browser"
};
Enumeration description
monitor a monitor display surface, physical display, or collection of physical displays
window a window display surface, or single application window
application an application display surface, or entire collection of windows for an application
browser a browser display surface, or single browser window

CursorCaptureConstraint

The CursorCaptureConstraint enumerates the conditions under which the cursor is captured.

enum CursorCaptureConstraint {
    "never",
    "always",
    "motion"
};
Enumeration description
never a never cursor capture constraint omits the cursor from the captured display surface.
always a always cursor capture constraint includes the cursor in the captured display surface.
motion a motion cursor capture constraint includes the cursor in the captured display surface when the cursor/pointer is moved. The captured cursor is removed when there is no further movement of the pointer/cursor for certain period of time, as determined by the user agent.

Device Identifiers

Each potential source of capture is treated by this API as a discrete media source. However, display capture sources MUST NOT be enumerated by enumerateDevices, since this would reveal too much information about the host system.

Display capture sources therefore cannot be selected with the deviceId constraint, since their deviceIds are not exposed.

This is not to be confused with the stable and private id of the same name used in algorithms to implement privacy indicators.

Feature Policy Integration

This specification defines a policy-controlled feature identified by the string "display-capture". Its default allowlist is "self".

A document's feature policy determines whether any content in that document is allowed to use getDisplayMedia. If disabled in any document, no content in the document will be allowed to use getDisplayMedia. This is enforced by the prompt the user to choose algorithm.

Privacy Indicator Requirements

This specification extends the Privacy Indicator Requirements of getUserMedia to include getDisplayMedia.

References in this specification to [[\devicesLiveMap]], [[\devicesAccessibleMap]], and [[\kindsAccessibleMap]] refer to the definitions already created to support Privacy Indicator Requirements for getUserMedia.

For each kind of device that getDisplayMedia exposes, using a stable and private id for the device, deviceId, set kind to "Display" + kind, and do the following:

Then, given the new definitions above, the requirements on the User Agent are those specified in Privacy Indicator Requirements of getUserMedia.

Even though there's a single permission descriptor for getDisplayMedia, the above definitions distinguish by kind to enable user agents to implement privacy indicators that show the end-user the specific kinds of display sources that are being shared at any point.

Since this specification forbids user agents from persisting "granted" permissions, only the "Live" indicators are significant.

The User Agent MUST NOT fire the devicechange event based on changes in the set of available sources from getDisplayMedia.

Security and Permissions

This section is informative; however, it notes some serious risks to platform security if the advice it contains are not adhered to.

This is consistent with other documents, but the absence of strong normative language here is a little worrying.

The risks to user privacy and security posed by capture of displayed content are twofold. The immediate and obvious risk is that users inadvertently share content that they did not wish to share, or might not have realized would be shared.

Display capture presents a less obvious risk to the cross site request forgery protections offered by the browser sandbox. Display and capture of information that is also under the control of an application, even indirectly, can allow that application to access information that would otherwise by inaccessible to it directly. For example, the canvas API does not permit sampling of a canvas, or conversion to an accessible form if it is not origin-clean [[2DCONTEXT]].

This issue is discussed in further detail in [[!RTCWEB-SECURITY-ARCH]] and [[!RTCWEB-SECURITY]].

Display capture that includes browser windows, particularly those that are under any form of control by the application, risks violation of these basic security protections. This risk is not entirely contained to browser windows, since control channels between browser applications and other applications, depending on the operating system. The key consideration is whether the captured display surface could be somehow induced to present information that would otherwise be secret from the application that is receiving the resulting media.

Capturing Logical or Visible Display Surfaces

Capture of logical display surfaces causes there to be a potential for content to be shared that a user is not made aware of. A logical display surface might render information that a user did not intend to expose. This can be more easily recognized if this information is visible. Such means are likely ineffectual against a machine, but a human recipient is less able to process content that appears only briefly.

Information that is not currently rendered to the screen SHOULD be obscured in captures unless the application has been specifically authorized to access that content (this might require elevated permissions).

How obscured areas of the logical display surface are captured to produce a visible display surface capture MAY vary. Some applications, like presentation software, benefit from having obscured portions of the screen render the image that appeared prior to being obscured. Freezing images can cause visual artifacts for changing content, or hide the fact that content is being obscured. Note that frozen portions of a capture can be incorrectly perceived as a bug. Alternatively, obscured areas might be replaced with content that marks them as being obscured, such as a grey color or hatching.

Some systems MAY only capture the logical display surface. Devices with small screens, for instance, do not typically have the concept of a window, and render applications in full screen modes only. These systems might provide a capture of an application that is not currently visible, which could be unusable without capturing the logical display surface.

An important consideration when capturing a window or other display surface that is partially transparent is that content from the background might be shared. A user agent MUST NOT capture content from the background of a captured display surface.

Authorizing Display Capture

This document provides recommends that implementations provide additional limitations on the mechanisms used to affirm user consent. These limitations are designed to mitigate the security and privacy risks that the API poses.

Two forms of consent interaction are described: active user consent and a range of elevated permissions. These are non-normative recommandations only.

Active User Consent

Active user consent is sufficient where there is little or no risk of an application gaining information that the user did not intend to share. These cases can be identified by those where the application that requests capture has no control over what is rendered to the captured display surface.

To prevent applications from limiting the available choices presented to a user with the goal of promoting a particular choice, the getDisplayMedia API does not permit the use of constraints to narrow the set of options presented.

Elevated Permissions

It is strongly advised that elevated permissions be required to access any display surface that might be used to circumvent cross-origin protections for content. The key goal of this consent process is not just to demonstrate that a user intends to share content, but to also to determine that the user exhibits an elevated level of trust in the application that is being granted access.

Several different controls might be provided to grant elevated permissions. This section describes several different capabilities that could be independently granted. A user agent might opt to prohibit access to any capability that requires elevated permissions.

If access to these surfaces is supported, it is strongly advised that any mechanism to acquire elevated permissions not rely solely on simple prompts for user consent. Any action needs to ensure that a decision to authorize an application with elevated privileges is deliberate. For instance, a user agent might require a process equivalent to software installation to signify that user consent for elevated permissions is granted.

An elevated permissions experience could allow the user agent to communicate the risks associated with enabling this feature, or at least to convey the need for augmented trust in the application.

Note that elevated permissions are not a substitute for active user consent. It is advised that user agents still present users with the ability to select what is shared, even for applications that have elevated permissions.

Capabilities Depending on Elevated Permissions

Elevated permissions are recommended as a prerequisite for access to capture of monitor or browser display surfaces. Note that capture of a complete monitor is included because this could include a window from the user agent.

Similarly, elevated permissions are a recommended prerequisite for access to logical display surfaces, where that would not ordinarily be provided.

A user agent SHOULD persist any elevated permissions that are granted to an origin. An elevated permissions process in part relies on its novelty to ensure that it correctly captures user intent.

Feedback and Interface During Capture

Implementations are advised to provide user feedback and control mechanisms similar to those offered users when sharing a camera or microphone, as recommended in [[GETUSERMEDIA]].

It is important that a user be aware that content is being shared when content is actively being captured. User agents are advised to display a prominent indicator while content is being captured. In addition to an indicator, a user agent is advised to provide a means to learn precisely what is being shared; while this capability is trivially provided by an application by rendering the captured content, this information allows a user to accurately assess what is being shared.

In addition to feedback mechanisms, a means to for the user to stop any active capture is advisable.