BackgroundFetchManager: fetch() method - Web APIs

BackgroundFetchManager: fetch() method
======================================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`fetch()`** method of the `BackgroundFetchManager` interface initiates a background fetch operation, given one or more URLs or `Request` objects.

Syntax
------

```js
fetch(id, requests)
fetch(id, requests, options)
```

### Parameters

`id`

A developer-defined identifier that can be passed to the other methods to retrieve the `BackgroundFetchRegistration` for this operation.

`requests`

A `RequestInfo` object or an array of `RequestInfo` objects.

Each `RequestInfo` object is a `Request` object or a string that will be given as the `input` argument to the `Request()` constructor.

`options` Optional

An object which will be used to customize the fetch progress dialog that the browser shows to the user. It has the following properties:

`title`

A string that will be used as the title for the progress dialog.

`icons`

An array of objects, each representing an icon that the browser may use for the progress dialog. Each object has the following properties:

`src`

A string representing a URL to the icon file.

`sizes`

A string representing the sizes of the image, expressed using the same syntax as the `sizes` attribute of the `<link>` element. Optional

`type`

A string representing the MIME type of the icon. Optional

`label`

A string representing the accessible name of the icon. Optional

`downloadTotal`

A number representing the estimated total download size, in bytes, for the fetch operation. This is used to show the user how big the download is and to show the user download progress.

As soon as the total download size exceeds `downloadTotal`, then the fetch is aborted.

### Return value

A `Promise` that resolves with a `BackgroundFetchRegistration` object.

### Exceptions

`TypeError`

Raised if no request is provided, if the mode of a request is 'no-cors', if no service worker is present, a request already exists with the requested `id`, or the request fails.

`AbortError` `DOMException`

Indicates that the fetch was aborted.

`NotAllowedError` `DOMException`

Indicates that user permission has not been granted to make background fetches.

Examples
--------

 The following example shows how to use `fetch()` to initiate a background fetch operation. With an active
 service worker, use the
 `ServiceWorkerRegistration.backgroundFetch` property to access the
 `BackgroundFetchManager` object and call its `fetch()`
 method.

```js
navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch(
    "my-fetch",
    ["/ep-5.mp3", "ep-5-artwork.jpg"],
    {
      title: "Episode 5: Interesting things.",
      icons: [
        {
          sizes: "300x300",
          src: "/ep-5-icon.png",
          type: "image/png",
          label: "Downloading a show",
        },
      ],
      downloadTotal: 60 \* 1024 \* 1024,
    },
  );
});
```

Specifications
--------------

| Specification |
| --- |
| Background Fetch # background-fetch-manager-fetch |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


BackgroundFetchManager: getIds() method - Web APIs

BackgroundFetchManager: getIds() method
=======================================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`getIds()`** method of the `BackgroundFetchManager` interface returns the IDs of all registered background fetches.

Syntax
------

```js
getIds()
```

### Parameters

None.

### Return value

A `Promise` that resolves with an `Array` of `strings`.

### Exceptions

None.

Examples
--------

The following examples shows how to retrieve the IDs of all registered background fetches. With an active service worker, use the `ServiceWorkerRegistration.backgroundFetch` property to access the `BackgroundFetchManager` object and call its `getIds()` method.

```js
navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});
```

Specifications
--------------

| Specification |
| --- |
| Background Fetch # background-fetch-manager-get-ids |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


BackgroundFetchManager: get() method - Web APIs

BackgroundFetchManager: get() method
====================================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`get()`** method of the `BackgroundFetchManager` interface returns a `Promise` that resolves with the `BackgroundFetchRegistration` associated with the provided `id` or `undefined` if the `id` is not found.

Syntax
------

```js
get(id)
```

### Parameters

`id`

The ID of a `backgroundFetchRegistration` defined by calling `fetch()`.

### Return value

A `Promise` that resolves with a `BackgroundFetchRegistration` or `undefined`.

Examples
--------

The following examples shows how to use `get()` to retrieve a `BackgroundFetchRegistration`. With an active `service worker`, use the `ServiceWorkerRegistration.backgroundFetch` to access the `BackgroundFetchManager` object and call its `get()` method.

```js
navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get("my-fetch");
});
// my code block
```

Specifications
--------------

| Specification |
| --- |
| Background Fetch # background-fetch-manager-get |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MediaError: message property - Web APIs

MediaError: message property
============================

 The read-only property **`MediaError.message`** returns a
 human-readable string offering specific
 diagnostic details related to the error described by the `MediaError` object,
 or an empty string (`""`) if no diagnostic information can be determined or
 provided.

Value
-----

 A string providing a detailed, specific explanation of what went
 wrong and possibly how it might be fixed. This is *not* a generic description of
 the `MediaError.code` property's value, but instead goes deeper into the
 specifics of this particular error and its circumstances. If no specific details are
 available, this string is empty.

Examples
--------

 This example creates a `<audio>` element, establishes an error handler
 for it, then lets the user click buttons to choose whether to assign a valid audio file
 or a missing file to the element's `src` attribute. The error
 handler outputs a message to a box onscreen describing the error, including both the
 `code` and the `message`.

Only the relevant parts of the code are displayed; you can see the complete source code here.

 The example creates an `<audio>` element and lets the user assign either
 a valid music file to it, or a link to a file which doesn't exist. This lets us see the
 behavior of the `error` event handler, which is received by an event handler
 we add to the `<audio>` element itself.

The error handler looks like this:

```js
audioElement.onerror = () => {
  let s = "";
  const err = audioElement.error;

  switch (err.code) {
    case MediaError.MEDIA\_ERR\_ABORTED:
      s += "The user canceled the audio.";
      break;
    case MediaError.MEDIA\_ERR\_NETWORK:
      s += "A network error occurred while fetching the audio.";
      break;
    case MediaError.MEDIA\_ERR\_DECODE:
      s += "An error occurred while decoding the audio.";
      break;
    case MediaError.MEDIA\_ERR\_SRC\_NOT\_SUPPORTED:
      s +=
        "The audio is missing or is in a format not supported by your browser.";
      break;
    default:
      s += "An unknown error occurred.";
      break;
  }

  const message = err.message;

  if (message?.length > 0) {
    s += ` ${message}`;
  }

  displayErrorMessage(`<strong>Error ${err.code}:</strong> ${s}<br>`);
};
```

 This gets the `MediaError` object describing the error from the
 `error` property on the
 `HTMLAudioElement` representing the audio player. The error's
 `code` attribute is checked to determine a generic error
 message to display, and, if `message` is not empty, it's appended to provide
 additional details. Then the resulting text is output to the log.

### Result

You can try out this example below, and can see the example in action outside this page here.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-mediaerror-message-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `MediaError`: Interface used to define the `MediaError.message` property
* `<audio>`, `<video>`


MediaError: msExtendedCode property - Web APIs

MediaError: msExtendedCode property
===================================

**Non-standard:** This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

In the event of an error, the media element's error event will be fired. The element's error property will then contain an **`msExtendedCode`** read-only property with platform-specific error code information.

**`msExtendedCode`** is a read-only proprietary property specific to Internet Explorer and Microsoft Edge.

Value
-----

Type: **long**; The platform specific error code.

Example
-------

```js
const video1 = object.getElementById("video1");

video1.addEventListener(
  "error",
  () => {
    const error = video1.error.msExtendedCode;
    //…
  },
  false,
);

video.addEventListener(
  "canplay",
  () => {
    video1.play();
  },
  false,
);
```


MediaError: code property - Web APIs

MediaError: code property
=========================

 The read-only property **`MediaError.code`** returns a numeric
 value which represents the kind of error that occurred on a media element. To get a text
 string with specific diagnostic information, see `MediaError.message`.

Value
-----

 A numeric value indicating the general type of error which occurred. The possible
 values are described below, in Media error code constants.

### Media error code constants

| Name | Value | Description |
| --- | --- | --- |
| `MEDIA_ERR_ABORTED` | `1` |
 The fetching of the associated resource was aborted by the user's
 request.
  |
| `MEDIA_ERR_NETWORK` | `2` |
 Some kind of network error occurred which prevented the media from being
 successfully fetched, despite having previously been available.
  |
| `MEDIA_ERR_DECODE` | `3` |
 Despite having previously been determined to be usable, an error
 occurred while trying to decode the media resource, resulting in an
 error.
  |
| `MEDIA_ERR_SRC_NOT_SUPPORTED` | `4` |
 The associated resource or media provider object (such as a
 `MediaStream`) has been found to be unsuitable.
  |

Examples
--------

 This example creates a `<video>` element, establishes an error handler
 for it, and then sets the element's `src` attribute to the
 video resource to present in the element. The error handler outputs a message

```js
const obj = document.createElement("video");
obj.onerror = () => {
  console.error(`Error with media: ${obj.error.code}`);
};
obj.src = "https://example.com/blahblah.mp4";
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-mediaerror-code-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `MediaError`: Interface used to define the `MediaError.code` property


LayoutShiftAttribution: toJSON() method - Web APIs

LayoutShiftAttribution: toJSON() method
=======================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`toJSON()`** method of the `LayoutShiftAttribution` interface is a *serializer* that returns a JSON representation of the `LayoutShiftAttribution` object.

Syntax
------

```js
toJSON()
```

### Parameters

None.

### Return value

A JSON object that is the serialization of the `LayoutShiftAttribution` object.

Examples
--------

The following example prints a JSON representation of the first item in `LayoutShift.sources` to the console.

```js
new PerformanceObserver((list) => {
  for (const { sources } of list.getEntries()) {
    if (sources) {
      console.log(sources[0].toJSON());
    }
  }
}).observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # sec-layout-shift-attribution |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


LayoutShiftAttribution: currentRect property - Web APIs

LayoutShiftAttribution: currentRect property
============================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`currentRect`** read-only property of the `LayoutShiftAttribution` interface returns a `DOMRectReadOnly` object representing the position of the element after the shift.

Value
-----

A `DOMRectReadOnly` object.

Examples
--------

The following example prints the `currentRect` of the first item in `LayoutShift.sources` to the console.

```js
new PerformanceObserver((list) => {
  for (const { sources } of list.getEntries()) {
    if (sources) {
      console.log(sources[0].currentRect);
    }
  }
}).observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshiftattribution-currentrect |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


LayoutShiftAttribution: node property - Web APIs

LayoutShiftAttribution: node property
=====================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`node`** read-only property of the `LayoutShiftAttribution` interface returns a `Node` representing the object that has shifted.

Value
-----

A `Node`.

Examples
--------

The following example prints the `node` of the first item in `LayoutShift.sources` to the console.

```js
new PerformanceObserver((list) => {
  for (const { sources } of list.getEntries()) {
    if (sources) {
      console.log(sources[0].node);
    }
  }
}).observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshiftattribution-node |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


LayoutShiftAttribution: previousRect property - Web APIs

LayoutShiftAttribution: previousRect property
=============================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`previousRect`** read-only property of the `LayoutShiftAttribution` interface returns a `DOMRectReadOnly` object representing the position of the element before the shift.

Value
-----

A `DOMRectReadOnly` object.

Examples
--------

The following example prints the `previousRect` of the first item in `LayoutShift.sources` to the console.

```js
new PerformanceObserver((list) => {
  for (const { sources } of list.getEntries()) {
    if (sources) {
      console.log(sources[0].previousRect);
    }
  }
}).observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshiftattribution-previousrect |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


WebGLActiveInfo: size property - Web APIs

WebGLActiveInfo: size property
==============================

The read-only **`WebGLActiveInfo.size`** property is a `Number` representing the size of the requested data returned by calling the `getActiveAttrib()` or `getActiveUniform()` methods.

Examples
--------

```js
const activeAttrib = gl.getActiveAttrib(program, index);
activeAttrib.size;

const activeUniform = gl.getActiveUniform(program, index);
activeUniform.size;
```

Specifications
--------------

| Specification |
| --- |
| WebGL Specification # DOM-WebGLActiveInfo-size |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `WebGLActiveInfo`


WebGLActiveInfo: name property - Web APIs

WebGLActiveInfo: name property
==============================

The read-only **`WebGLActiveInfo.name`** property represents the name of the requested data returned by calling the `getActiveAttrib()` or `getActiveUniform()` methods.

Examples
--------

```js
const activeAttrib = gl.getActiveAttrib(program, index);
activeAttrib.name;

const activeUniform = gl.getActiveUniform(program, index);
activeUniform.name;
```

Specifications
--------------

| Specification |
| --- |
| WebGL Specification # DOM-WebGLActiveInfo-name |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `WebGLActiveInfo`


WebGLActiveInfo: type property - Web APIs

WebGLActiveInfo: type property
==============================

The read-only **`WebGLActiveInfo.type`** property represents the type of the requested data returned by calling the `getActiveAttrib()` or `getActiveUniform()` methods.

Examples
--------

```js
const activeAttrib = gl.getActiveAttrib(program, index);
activeAttrib.type;

const activeUniform = gl.getActiveUniform(program, index);
activeUniform.type;
```

Specifications
--------------

| Specification |
| --- |
| WebGL Specification # DOM-WebGLActiveInfo-type |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `WebGLActiveInfo`


Using the Gamepad API - Web APIs

Using the Gamepad API
=====================

HTML provides the necessary components for rich, interactive game development. Technologies like `<canvas>`, WebGL, `<audio>`, and `<video>`, along with JavaScript implementations, support tasks that provide similar, if not the same, features as native code. The Gamepad API allows developers and designers to access and use gamepads and other game controllers.

The Gamepad API introduces new events on the `Window` object for reading gamepad and controller (hereby referred to as *gamepad*) state. In addition to these events, the API also adds a `Gamepad` object, which you can use to query the state of a connected gamepad, and a `navigator.getGamepads()` method which you can use to get a list of gamepads known to the page.

Connecting to a gamepad
-----------------------

When a new gamepad is connected to the computer, the focused page first receives a `gamepadconnected` event. If a gamepad is already connected when the page loaded, the `gamepadconnected` event is dispatched to the focused page when the user presses a button or moves an axis.

**Note:** In Firefox, gamepads are only exposed to a page when the user interacts with one with the page visible. This helps prevent gamepads from being used for fingerprinting the user. Once one gamepad has been interacted with, other gamepads that are connected will automatically be visible.

You can use `gamepadconnected` like this:

```js
window.addEventListener("gamepadconnected", (e) => {
  console.log(
    "Gamepad connected at index %d: %s. %d buttons, %d axes.",
    e.gamepad.index,
    e.gamepad.id,
    e.gamepad.buttons.length,
    e.gamepad.axes.length,
  );
});
```

Each gamepad has a unique ID associated with it, which is available on the event's `gamepad` property.

Disconnecting a gamepad
-----------------------

When a gamepad is disconnected, and if a page has previously received data for that gamepad (e.g. `gamepadconnected`), a second event is dispatched to the focused window, `gamepaddisconnected`:

```js
window.addEventListener("gamepaddisconnected", (e) => {
  console.log(
    "Gamepad disconnected from index %d: %s",
    e.gamepad.index,
    e.gamepad.id,
  );
});
```

The gamepad's `index` property will be unique per-device connected to the system, even if multiple controllers of the same type are used. The `index` property also functions as the index into the `Array` returned by `Navigator.getGamepads()`.

```js
const gamepads = {};

function gamepadHandler(event, connected) {
  const gamepad = event.gamepad;
  // Note:
  // gamepad === navigator.getGamepads()[gamepad.index]

  if (connected) {
    gamepads[gamepad.index] = gamepad;
  } else {
    delete gamepads[gamepad.index];
  }
}

window.addEventListener(
  "gamepadconnected",
  (e) => {
    gamepadHandler(e, true);
  },
  false,
);
window.addEventListener(
  "gamepaddisconnected",
  (e) => {
    gamepadHandler(e, false);
  },
  false,
);
```

This previous example also demonstrates how the `gamepad` property can be held after the event has completed — a technique we will use for device state querying later.

Querying the Gamepad object
---------------------------

As you can see, the **gamepad** events discussed above include a `gamepad` property on the event object, which returns a `Gamepad` object. We can use this in order to determine which gamepad (i.e., its ID) had caused the event, since multiple gamepads might be connected at once. We can do much more with the `Gamepad` object, including holding a reference to it and querying it to find out which buttons and axes are being pressed at any one time. Doing so is often desirable for games or other interactive web pages that need to know the state of a gamepad now vs. the next time an event fires.

Performing such checks tends to involve using the `Gamepad` object in conjunction with an animation loop (e.g., `requestAnimationFrame`), where developers want to make decisions for the current frame based on the state of the gamepad or gamepads.

The `Navigator.getGamepads()` method returns an array of all devices currently visible to the webpage, as `Gamepad` objects (the first value is always `null`, so `null` will be returned if there are no gamepads connected.) This can then be used to get the same information. For example, the first code example above could be rewritten as shown below:

```js
window.addEventListener("gamepadconnected", (e) => {
  const gp = navigator.getGamepads()[e.gamepad.index];
  console.log(
    "Gamepad connected at index %d: %s. %d buttons, %d axes.",
    gp.index,
    gp.id,
    gp.buttons.length,
    gp.axes.length,
  );
});
```

The `Gamepad` object's properties are as follows:

* `id`: A string containing some information about the controller. This is not strictly specified, but in Firefox it will contain three pieces of information separated by dashes (`-`): two 4-digit hexadecimal strings containing the USB vendor and product id of the controller, and the name of the controller as provided by the driver. This information is intended to allow you to find a mapping for the controls on the device as well as display useful feedback to the user.
* `index`: An integer that is unique for each gamepad currently connected to the system. This can be used to distinguish multiple controllers. Note that disconnecting a device and then connecting a new device may reuse the previous index.
* `mapping`: A string indicating whether the browser has remapped the controls on the device to a known layout. Currently there is only one supported known layout — the standard gamepad. If the browser is able to map controls on the device to that layout the `mapping` property will be set to the string `standard`.
* `connected`: A boolean indicating whether the gamepad is still connected to the system. If this is so the value is `True`; if not, it is `False`.
* `buttons`: An array of `GamepadButton` objects representing the buttons present on the device. Each `GamepadButton` has a `pressed` and a `value` property:
    + The `pressed` property is a boolean indicating whether the button is currently pressed (`true`) or unpressed (`false`).
    + The `value` property is a floating point value used to enable representing analog buttons, such as the triggers on many modern gamepads. The values are normalized to the range 0.0..1.0, with 0.0 representing a button that is not pressed, and 1.0 representing a button that is fully pressed.
* `axes`: An array representing the controls with axes present on the device (e.g. analog thumb sticks). Each entry in the array is a floating point value in the range -1.0 - 1.0, representing the axis position from the lowest value (-1.0) to the highest value (1.0).
* `timestamp`: This returns a `DOMHighResTimeStamp` representing the last time the data for this gamepad was updated, allowing developers to determine if the `axes` and `button` data have been updated from the hardware. The value must be relative to the `navigationStart` attribute of the `PerformanceTiming` interface. Values are monotonically increasing, meaning that they can be compared to determine the ordering of updates, as newer values will always be greater than or equal to older values. Note that this property is not currently supported in Firefox.

**Note:** The Gamepad object is available on the `gamepadconnected` event rather than the `Window` object itself, for security reasons. Once we have a reference to it, we can query its properties for information about the current state of the gamepad. Behind the scenes, this object will be updated every time the gamepad's state changes.

### Using button information

Let's look at a simple example that displays connection information for one gamepad (it ignores subsequent gamepad connections) and allows you to move a ball around the screen using the four gamepad buttons on the right-hand side of the gamepad. You can view the demo live, and find the source code on GitHub.

To start with, we declare some variables: The `gamepadInfo` paragraph that the connection info is written into, the `ball` that we want to move, the `start` variable that acts as the ID for `requestAnimation Frame`, the `a` and `b` variables that act as position modifiers for moving the ball, and the shorthand variables that will be used for the `requestAnimationFrame()` and `cancelAnimationFrame()` cross browser forks.

```js
const gamepadInfo = document.getElementById("gamepad-info");
const ball = document.getElementById("ball");
let start;
let a = 0;
let b = 0;
```

Next we use the `gamepadconnected` event to check for a gamepad being connected. When one is connected, we grab the gamepad using `Navigator.getGamepads()``[0]`, print information about the gamepad into our gamepad info `div`, and fire the `gameLoop()` function that starts the whole ball movement process up.

```js
window.addEventListener("gamepadconnected", (e) => {
  const gp = navigator.getGamepads()[e.gamepad.index];
  gamepadInfo.textContent = `Gamepad connected at index ${gp.index}: ${gp.id}. It has ${gp.buttons.length} buttons and ${gp.axes.length} axes.`;

  gameLoop();
});
```

Now we use the `gamepaddisconnected` event to check if the gamepad is disconnected again. If so, we stop the `requestAnimationFrame()` loop (see below) and revert the gamepad information back to what it was originally.

```js
window.addEventListener("gamepaddisconnected", (e) => {
  gamepadInfo.textContent = "Waiting for gamepad.";

  cancelAnimationFrame(start);
});
```

Chrome does things differently here. Instead of constantly storing the gamepad's latest state in a variable it only stores a snapshot, so to do the same thing in Chrome you have to keep polling it and then only use the `Gamepad` object in code when it is available. We have done this below using `setInterval()`; once the object is available the gamepad info is outputted, the game loop is started, and the interval is cleared using `clearInterval`.

```js
let interval;

if (!("ongamepadconnected" in window)) {
  // No gamepad events available, poll instead.
  interval = setInterval(pollGamepads, 500);
}

function pollGamepads() {
  const gamepads = navigator.getGamepads();
  for (const gp of gamepads) {
    gamepadInfo.textContent = `Gamepad connected at index ${gp.index}: ${gp.id}. It has ${gp.buttons.length} buttons and ${gp.axes.length} axes.`;
    gameLoop();
    clearInterval(interval);
  }
}
```

Now on to the main game loop. In each execution of the loop we check if one of four buttons is being pressed; if so, we update the values of the `a` and `b` movement variables appropriately, then update the `left` and `top` properties, changing their values to the current values of `a` and `b` respectively. This has the effect of moving the ball around the screen.

After all this is done, we use our `requestAnimationFrame()` to request the next animation frame, running `gameLoop()` again.

```js
function buttonPressed(b) {
  if (typeof b === "object") {
    return b.pressed;
  }
  return b === 1.0;
}

function gameLoop() {
  const gamepads = navigator.getGamepads();
  if (!gamepads) {
    return;
  }

  const gp = gamepads[0];
  if (buttonPressed(gp.buttons[0])) {
    b--;
  } else if (buttonPressed(gp.buttons[2])) {
    b++;
  }
  if (buttonPressed(gp.buttons[1])) {
    a++;
  } else if (buttonPressed(gp.buttons[3])) {
    a--;
  }

  ball.style.left = `${a \* 2}px`;
  ball.style.top = `${b \* 2}px`;

  start = requestAnimationFrame(gameLoop);
}
```

Complete example: Displaying gamepad state
------------------------------------------

This example shows how to use the `Gamepad` object, as well as the `gamepadconnected` and `gamepaddisconnected` events in order to display the state of all gamepads connected to the system. You can find a working demo and look at the full source code on GitHub.

```js
const haveEvents = "ongamepadconnected" in window;
const controllers = {};

function connecthandler(e) {
  addgamepad(e.gamepad);
}

function addgamepad(gamepad) {
  controllers[gamepad.index] = gamepad;

  const d = document.createElement("div");
  d.setAttribute("id", `controller${gamepad.index}`);

  const t = document.createElement("h1");
  t.textContent = `gamepad: ${gamepad.id}`;
  d.appendChild(t);

  const b = document.createElement("ul");
  b.className = "buttons";
  gamepad.buttons.forEach((button, i) => {
    const e = document.createElement("li");
    e.className = "button";
    e.textContent = `Button ${i}`;
    b.appendChild(e);
  });

  d.appendChild(b);

  const a = document.createElement("div");
  a.className = "axes";

  gamepad.axes.forEach((axis, i) => {
    const p = document.createElement("progress");
    p.className = "axis";
    p.setAttribute("max", "2");
    p.setAttribute("value", "1");
    p.textContent = i;
    a.appendChild(p);
  });

  d.appendChild(a);

  // See https://github.com/luser/gamepadtest/blob/master/index.html
  const start = document.getElementById("start");
  if (start) {
    start.style.display = "none";
  }

  document.body.appendChild(d);
  requestAnimationFrame(updateStatus);
}

function disconnecthandler(e) {
  removegamepad(e.gamepad);
}

function removegamepad(gamepad) {
  const d = document.getElementById(`controller${gamepad.index}`);
  document.body.removeChild(d);
  delete controllers[gamepad.index];
}

function updateStatus() {
  if (!haveEvents) {
    scangamepads();
  }

  Object.entries(controllers).forEach(([i, controller]) => {
    const d = document.getElementById(`controller${i}`);
    const buttons = d.getElementsByClassName("button");

    controller.buttons.forEach((button, i) => {
      const b = buttons[i];
      let pressed = button === 1.0;
      let val = button;

      if (typeof button === "object") {
        pressed = val.pressed;
        val = val.value;
      }

      const pct = `${Math.round(val \* 100)}%`;
      b.style.backgroundSize = `${pct} ${pct}`;
      b.textContent = pressed ? `Button ${i} [PRESSED]` : `Button ${i}`;
      b.style.color = pressed ? "#42f593" : "#2e2d33";
      b.className = pressed ? "button pressed" : "button";
    });

    const axes = d.getElementsByClassName("axis");
    controller.axes.forEach((axis, i) => {
      const a = axes[i];
      a.textContent = `${i}: ${axis.toFixed(4)}`;
      a.setAttribute("value", axis + 1);
    });
  });

  requestAnimationFrame(updateStatus);
}

function scangamepads() {
  const gamepads = navigator.getGamepads();
  document.querySelector("#noDevices").style.display = gamepads.filter(Boolean)
    .length
    ? "none"
    : "block";
  for (const gamepad of gamepads) {
    if (gamepad) {
      // Can be null if disconnected during the session
      if (gamepad.index in controllers) {
        controllers[gamepad.index] = gamepad;
      } else {
        addgamepad(gamepad);
      }
    }
  }
}

window.addEventListener("gamepadconnected", connecthandler);
window.addEventListener("gamepaddisconnected", disconnecthandler);

if (!haveEvents) {
  setInterval(scangamepads, 500);
}
```

Specifications
--------------

| Specification |
| --- |
| Gamepad # gamepad-interface |
| Gamepad Extensions # partial-gamepad-interface |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSContainerRule: containerQuery property - Web APIs

CSSContainerRule: containerQuery property
=========================================

The read-only **`containerQuery`** property of the `CSSContainerRule` interface returns a string representing the container conditions that are evaluated when the container changes size in order to determine if the styles in the associated `@container` are applied.

For example, the value of `containerQuery` for the `@container` below is `(min-width: 700px)`:

```css
@container sidebar (min-width: 700px) {
  .card {
    font-size: 2em;
  }
}
```

Value
-----

A string containing the container query.

Note that the value may not be identical to the original string, as normalizations such as removing whitespace may happen.

Examples
--------

 The example below defines an unnamed `@container` rule, and displays the properties of the associated `CSSContainerRule`.
 The CSS is the same as in the `@container` example Setting styles based on a container's size.
```

<div id="log">
  <h2>Log</h2>
  <ul></ul>
  <hr />
</div>
```

```
// Store reference to log list
const logList = document.querySelector("#log ul");
// Function to log data from underlying source
function log(result) {
  const listItem = document.createElement("li");
  listItem.textContent = result;
  logList.appendChild(listItem);
}
```

First we define the HTML for a `card` (`<div>`) contained within a `post`.

```html
<div class="post">
  <div class="card">
    <h2>Card title</h2>
    <p>Card content</p>
  </div>
</div>
```

 The CSS for the container element specifies the type of the container.
 The `@container` then applies a new width, font-size and background color to the contained element "card" if the width is less than 650px.

```html
<style id="examplestyles">
 /\* A container context based on inline size \*/
 .post {
 container-type: inline-size;
 }

 /\* Apply styles if the container is narrower than 650px \*/
 @container (width < 650px) {
 .card {
 width: 50%;
 background-color: gray;
 font-size: 1em;
 }
 }
</style>
```

 The code below gets the `HTMLStyleElement` associated with the example using its id, and then uses its `sheet` property to get the `StyleSheet`.
 From the `StyleSheet` we get the set of `cssRules` added to the sheet.
 Since we added the `@container` as the second rule above, we can access the associated `CSSContainerRule` using the second entry (with index "1"), in the `cssRules`.
 Last of all, we log the container name and query properties.

```js
const exampleStylesheet = document.getElementById("examplestyles").sheet;
const exampleRules = exampleStylesheet.cssRules;
const containerRule = exampleRules[1]; // a CSSContainerRule representing the container rule.
log(`CSSContainerRule.containerQuery: "${containerRule.containerQuery}"`);
```

 The example output is shown below.
 The log section lists the query string.
 The card should change background and as the width of the page transitions through 650px.

Specifications
--------------

| Specification |
| --- |
| CSS Containment Module Level 3 # dom-csscontainerrule-containerquery |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSContainerRule: containerName property - Web APIs

CSSContainerRule: containerName property
========================================

The read-only **`containerName`** property of the `CSSContainerRule` interface represents the container name of the associated CSS `@container` at-rule.

For example, the value of `containerName` for the `@container` below is `sidebar`:

```css
@container sidebar (min-width: 700px) {
  .card {
    font-size: 2em;
  }
}
```

Value
-----

 A string that contains the `container-name` of the `@container` associated with this `CSSContainerRule`.
 If the `@container` is not named, the function returns the empty string (`""`).

Examples
--------

 The example below defines a named `@container` rule, and displays the properties of the associated `CSSContainerRule`.
 The CSS is very similar to that in the `@container` example Creating named container contexts.
```

<div id="log">
  <h2>Log</h2>
  <ul></ul>
  <hr />
</div>
```

```
// Store reference to log list
const logList = document.querySelector("#log ul");
// Function to log data from underlying source
function log(result) {
  const listItem = document.createElement("li");
  listItem.textContent = result;
  logList.appendChild(listItem);
}
```

First we define the HTML for a `card` (`<div>`) contained within a `post`.

```html
<div class="post">
  <div class="card">
    <h2>Card title</h2>
    <p>Card content</p>
  </div>
</div>
```

 The CSS for the container element specifies the type of the container, and may also specify a name.
 The card has a default font size, which is overridden for the `@container` named `sidebar` if the minimum width is greater than 700px.

```html
<style id="examplestyles">
 .post {
 container-type: inline-size;
 container-name: sidebar;
 }

 /\* Default heading styles for the card title \*/
 .card h2 {
 font-size: 1em;
 }

 @container sidebar (min-width: 700px) {
 .card {
 font-size: 2em;
 }
 }
</style>
```

 The code below gets the `HTMLStyleElement` associated with the example using its `id`, and then uses its `sheet` property to get the `StyleSheet`.
 From the `StyleSheet` we get the set of `cssRules` added to the sheet.
 Since we added the `@container` as the third rule above, we can access the associated `CSSContainerRule` using the third entry (index "2"), in the `cssRules`.
 Last of all, we log the container name and query properties (the code that does the logging is not shown).

```js
const exampleStylesheet = document.getElementById("examplestyles").sheet;
const exampleRules = exampleStylesheet.cssRules;
const containerRule = exampleRules[2]; // a CSSContainerRule representing the container rule.
log(`CSSContainerRule.containerName: "${containerRule.containerName}"`);
```

 The example output is shown below.
 The log section lists the container name string.
 The title in the card section should double in size as the width of the page goes over 700px.

Specifications
--------------

| Specification |
| --- |
| CSS Containment Module Level 3 # dom-csscontainerrule-containername |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


RTCErrorEvent: error property - Web APIs

RTCErrorEvent: error property
=============================

 The read-only `RTCErrorEvent` property **`error`**
 contains an `RTCError` object describing the details of the error which the
 event is announcing.

Value
-----

 An `RTCError` object whose properties provide details about the error
 which has occurred in the context of a WebRTC operation.

Examples
--------

 In this example, a handler is established for an `RTCDataChannel`'s
 `error` event.

```js
dataChannel.addEventListener("error", (event) => {
  let error = event.error;

  if (error.errorDetail === "sdp-syntax-error") {
    let errLine = error.sdpLineNumber;
    let errMessage = error.message;

    let alertMessage = `A syntax error occurred interpreting line ${errLine} of the SDP: ${errMessage}`;
    showMyAlertMessage("Data Channel Error", alertMessage);
  } else {
    terminateMyConnection();
  }
});
```

 If the error is an SDP syntax error—indicated by its `errorDetail` property being `sdp-syntax-error`—, a message string is
 constructed to present the error message and the line number within the SDP at which the
 error occurred. This message is then displayed using a function called
 `showMyAlertMessage()`, which stands in for whatever output mechanism this
 code might use.

 Any other error is treated as terminal, causing a `terminateMyConnection()`
 function to be called.

 The above example uses `addEventListener()` to add the handler for `error` events. You can also
 use the `RTCDataChannel` object's `onerror` event handler property, like this:

```js
dataChannel.onerror = (event) => {
  let error = event.error;

  /\* and so forth \*/
};
```

Specifications
--------------

| Specification |
| --- |
| WebRTC: Real-Time Communication in Browsers # dom-rtcerrorevent-error |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSKeyframesRule: deleteRule() method - Web APIs

CSSKeyframesRule: deleteRule() method
=====================================

The **`deleteRule()`** method of the `CSSKeyframeRule` interface deletes the `CSSKeyFrameRule` that matches the specified keyframe selector.

Syntax
------

```js
deleteRule(select)
```

### Parameters

`select`

A string which contains the keyframe selector of the rule to be deleted, which must be:

* a comma-separated list of percentage values between 0% and 100%;
* or, the keywords `from` or `to`

Note that the number and order of the values in the specified keyframe selector must match those of the targeted keyframe rule(s). White-space is disregarded.

### Return value

None (`undefined`).

Examples
--------

 The CSS includes a keyframes at-rule. This will be the first `CSSRule` returned by `document.styleSheets[0].cssRules`.
 `myRules[0]` returns a `CSSKeyframesRule` object. Returning the `cssRules` property would return a `CSSRuleList` containing two rules.

After deleting a rule with `deleteRule()` the `cssRules` property returns a `CSSRuleList` containing one rule.

```css
@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}
```

```js
let myRules = document.styleSheets[0].cssRules;
let keyframes = myRules[0]; // a CSSKeyframesRule
keyframes.deleteRule("to");
console.log(keyframes.cssRules); // a CSSRuleList object with one rule
```

Specifications
--------------

| Specification |
| --- |
| CSS Animations Level 1 # dom-csskeyframesrule-deleterule |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSKeyframesRule: findRule() method - Web APIs

CSSKeyframesRule: findRule() method
===================================

The **`findRule()`** method of the `CSSKeyframeRule` interface finds the `CSSKeyFrameRule` that matches the specified keyframe selector.

Syntax
------

```js
findRule(select)
```

### Parameters

`select`

A string which contains the keyframe selector of the rule to be found, which must be:

* a comma-separated list of percentage values between 0% and 100%;
* or, the keywords `from` or `to`

Note that the number and order of the values in the specified keyframe selector must match those of the targeted keyframe rule(s). White-space is disregarded.

### Return value

A `CSSKeyframeRule` which is the last matching rule. If no rules are found, nothing is returned.

Examples
--------

 The CSS includes a keyframes at-rule. This will be the first `CSSRule` returned by `document.styleSheets[0].cssRules`.
 `myRules[0]` returns a `CSSKeyframesRule` object. Calling findRule("to") returns a `CSSKeyframeRule` representing the second rule.

```css
@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}
```

```js
let myRules = document.styleSheets[0].cssRules;
let keyframes = myRules[0]; // a CSSKeyframesRule
console.log(keyframes.findRule("to")); // a CSSKeyframeRule object
```

Specifications
--------------

| Specification |
| --- |
| CSS Animations Level 1 # interface-csskeyframesrule-findrule |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSKeyframesRule: name property - Web APIs

CSSKeyframesRule: name property
===============================

The **`name`** property of the `CSSKeyframeRule` interface gets and sets the name of the animation as used by the `animation-name` property.

Value
-----

A string.

Examples
--------

 The CSS includes a keyframes at-rule. This will be the first `CSSRule` returned by `document.styleSheets[0].cssRules`.
 `myRules[0]` returns a `CSSKeyframesRule` object, with the `name` set to "slidein".

```css
@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}
```

```js
let myRules = document.styleSheets[0].cssRules;
let keyframes = myRules[0]; // a CSSKeyframesRule
console.log(keyframes.name); // "slidein"
```

Specifications
--------------

| Specification |
| --- |
| CSS Animations Level 1 # dom-csskeyframesrule-name |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSKeyframesRule: appendRule() method - Web APIs

CSSKeyframesRule: appendRule() method
=====================================

The **`appendRule()`** method of the `CSSKeyframeRule` interface appends a `CSSKeyFrameRule` to the end of the rules.

Syntax
------

```js
appendRule(rule)
```

### Parameters

`rule`

A string containing a keyframe rule.

### Return value

None (`undefined`).

Examples
--------

 The CSS includes a keyframes at-rule. This will be the first `CSSRule` returned by `document.styleSheets[0].cssRules`.
 `myRules[0]` returns a `CSSKeyframesRule` object. Returning the `cssRules` property would return a `CSSRuleList` containing one rule.

After appending another rule with `appendRule` the `cssRules` property returns a `CSSRuleList` containing two rules.

```css
@keyframes slidein {
  from {
    transform: translateX(0%);
  }
}
```

```js
let myRules = document.styleSheets[0].cssRules;
let keyframes = myRules[0]; // a CSSKeyframesRule
keyframes.appendRule("to {transform: translateX(100%);}");
console.log(keyframes.cssRules); // a CSSRuleList object with two rules
```

Specifications
--------------

| Specification |
| --- |
| CSS Animations Level 1 # interface-csskeyframesrule-appendrule |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


CSSKeyframesRule: cssRules property - Web APIs

CSSKeyframesRule: cssRules property
===================================

The read-only **`cssRules`** property of the `CSSKeyframeRule` interface returns a `CSSRuleList` containing the rules in the keyframes at-rule.

Value
-----

A `CSSRuleList`.

Examples
--------

 The CSS includes a keyframes at-rule. This will be the first `CSSRule` returned by `document.styleSheets[0].cssRules`.
 `myRules[0]` returns a `CSSKeyframesRule` object. The `cssRules` property returns a `CSSRuleList` containing two rules.

```css
@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}
```

```js
let myRules = document.styleSheets[0].cssRules;
let keyframes = myRules[0]; // a CSSKeyframesRule
console.log(keyframes.cssRules); // a CSSRuleList object with two rules
```

Specifications
--------------

| Specification |
| --- |
| CSS Animations Level 1 # dom-csskeyframesrule-cssrules |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MediaDevices: enumerateDevices() method - Web APIs

MediaDevices: enumerateDevices() method
=======================================

 The `MediaDevices` method **`enumerateDevices()`** requests a list of the currently available media input and output devices, such as microphones, cameras, headsets, and so forth.
 The returned `Promise` is resolved with an array of `MediaDeviceInfo` objects describing the devices.

 The returned list will omit any devices that are blocked by the document Permission Policy: `microphone`, `camera`, `speaker-selection` (for output devices), and so on.
 Access to particular non-default devices is also gated by the Permissions API, and the list will omit devices for which the user has not granted explicit permission.

Syntax
------

```js
enumerateDevices()
```

### Parameters

None.

### Return value

 A `Promise` that is fulfilled with an array of `MediaDeviceInfo` objects.
 Each object in the array describes one of the available media input and output devices.
 The order is significant — the default capture devices will be listed first.

Other than default devices, only devices for which permission has been granted are "available".

If enumeration fails, the promise is rejected.

Security requirements
---------------------

Access to the API is subject to the following constraints:

* The method must be called in a secure context.
Examples
--------

Here's an example of using `enumerateDevices()`. It outputs a list of the device IDs, with their labels if available.

```js
if (!navigator.mediaDevices?.enumerateDevices) {
  console.log("enumerateDevices() not supported.");
} else {
  // List cameras and microphones.
  navigator.mediaDevices
    .enumerateDevices()
    .then((devices) => {
      devices.forEach((device) => {
        console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
      });
    })
    .catch((err) => {
      console.error(`${err.name}: ${err.message}`);
    });
}
```

This might produce:
```

videoinput: id = csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8=
audioinput: id = RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM=
audioinput: id = r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0=
```

 or if one or more `MediaStream`s are active or persistent permissions are
 granted:
```

videoinput: FaceTime HD Camera (Built-in) id=csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8=
audioinput: default (Built-in Microphone) id=RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM=
audioinput: Built-in Microphone id=r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0=
```

Specifications
--------------

| Specification |
| --- |
| Media Capture and Streams # dom-mediadevices-enumeratedevices |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `MediaDevices.getUserMedia`
* WebRTC - the introductory page to the API
* Media Capture and Streams API - the API for the media stream objects
* Taking webcam photos - a
 tutorial on using `getUserMedia()` for taking photos rather than video.


MediaDevices: getDisplayMedia() method - Web APIs

MediaDevices: getDisplayMedia() method
======================================

 The **`getDisplayMedia()`** method of the `MediaDevices` interface prompts the user to select and
 grant permission to capture the contents of a display or portion thereof (such as a window) as a `MediaStream`.

 The resulting stream can then be
 recorded using the MediaStream Recording API or transmitted as part of a WebRTC session.

See Using the Screen Capture API for more details and an example.

Syntax
------

```js
getDisplayMedia()
getDisplayMedia(options)
```

### Parameters

`options` Optional

An optional object specifying requirements for the returned `MediaStream`. The options for `getDisplayMedia()` work in the same as the constraints for the `MediaDevices.getUserMedia()` method, although in that case only `audio` and `video` can be specified. The list of possible option properties for `getDisplayMedia()` is as follows:

`video` Optional

A boolean or a `MediaTrackConstraints` instance; the default value is `true`. If this option is omitted or set to `true`, the stream will contain a video track A value of `true` indicates that the returned `MediaStream` will contain a video track. Since `getDisplayMedia()` requires a video track, if this option is set to `false` the promise will reject with a `TypeError`.

`audio` Optional

A boolean or a `MediaTrackConstraints` instance; the default value is `false`. A value of `true` indicates that the returned `MediaStream` will contain an audio track, if audio is supported and available for the display surface chosen by the user.

`controller`
Experimental
 Optional

A `CaptureController` object instance containing methods that can be used to further manipulate the capture session if included.

`monitorTypeSurfaces` Optional

An enumerated value specifying whether the browser should offer entire screens in the screen capture options presented to the user alongside tab and window options. This option is intended to protect companies from leakage of private information through employee error when using video conferencing apps. Possible values are `include`, which hints that the browser should include screen options, and `exclude`, which hints that they should be excluded. A default value is not mandated by the spec; see the Browser compatibility section for browser-specific defaults.

**Note:** You cannot set `monitorTypeSurfaces: "exclude"` at the same time as `displaySurface: "monitor"` as the two settings are contradictory. Trying to do so will result in the `getDisplayMedia()` call failing with a `TypeError`.

`preferCurrentTab`
Non-standard

Experimental
 Optional

A boolean; a value of `true` instructs the browser to offer the current tab as the most prominent capture source, i.e. as a separate "This Tab" option in the "Choose what to share" options presented to the user. This is useful as many app types generally just want to share the current tab. For example, a slide deck app might want to let the user stream the current tab containing the presentation to a virtual conference. A default value is not mandated by the spec; see the Browser compatibility section for browser-specific defaults.

`selfBrowserSurface`
Experimental
 Optional

An enumerated value specifying whether the browser should allow the user to select the current tab for capture. This helps to avoid the "infinite hall of mirrors" effect experienced when a video conferencing app inadvertently shares its own display. Possible values are `include`, which hints that the browser should include the current tab in the choices offered for capture, and `exclude`, which hints that it should be excluded. A default value is not mandated by the spec; see the Browser compatibility section for browser-specific defaults.

`surfaceSwitching`
Experimental
 Optional

An enumerated value specifying whether the browser should display a control to allow the user to dynamically switch the shared tab during screen-sharing. This is much more convenient than having to go through the whole sharing process again each time a user wants to switch the shared tab. Possible values are `include`, which hints that the browser should include the control, and `exclude`, which hints that it should not be shown. A default value is not mandated by the spec; see the Browser compatibility section for browser-specific defaults.

`systemAudio`
Experimental
 Optional

An enumerated value specifying whether the browser should include the system audio among the possible audio sources offered to the user. Possible values are `include`, which hints that the browser should include the system audio in the list of choices, and `exclude`, which hints that it should be excluded. A default value is not mandated by the spec; see the Browser compatibility section for browser-specific defaults.

`monitorTypeSurfaces`
Experimental
 Optional

An enumerated value specifying whether the application would like the user agent to offer the user the option to choose display surfaces whose type is monitor. Possible values are `include`, which hints that the browser should include the display surfaces whose type is monitor, and `exclude`, which hints that it should be excluded. A default value is not mandated by the spec; see the Browser compatibility section for browser-specific defaults.

**Note:** See the article Capabilities, constraints, and settings for a lot more detail on how these options work.

### Return value

 A `Promise` that resolves to a `MediaStream` containing a
 video track whose contents come from a user-selected screen area, as well as an optional
 audio track.

**Note:** Browser support for audio tracks varies, both in terms of whether or not they're supported at all by the media recorder and in terms of the audio sources supported. Check the compatibility table for details for each browser.

### Exceptions

`AbortError` `DOMException`

Thrown if an error or failure does not match any of the other exceptions listed here.

`InvalidStateError` `DOMException`

 Thrown if the call to `getDisplayMedia()` was not made from code running due to a
 transient activation, such as an event handler. Or if the browser context is
 not fully active or does not focused. Or if the `controller` options has been already used in creating
 another `MediaStream`.

`NotAllowedError` `DOMException`

Thrown if the permission to access a screen area was denied by the user, or the current browsing instance is not permitted access to screen sharing (for example by a Permissions Policy).

`NotFoundError` `DOMException`

Thrown if no sources of screen video are available for capture.

`NotReadableError` `DOMException`

 Thrown if the user selected a screen, window, tab, or another source of screen data, but a
 hardware or operating system level error or lockout occurred, preventing the sharing
 of the selected source.

`OverconstrainedError` `DOMException`

 Thrown if, after creating the stream, applying any specified constraints fails
 because no compatible stream could be generated.

`TypeError`

 Thrown if the specified `options` include values that are not permitted
 when calling `getDisplayMedia()`, for example a `video` property set to false, or if any specified `MediaTrackConstraints` are not permitted. `min` and `exact` values are not permitted in constraints used in `getDisplayMedia()` calls.

Security
--------

 Because `getDisplayMedia()` could be used in nefarious ways, it can be a
 source of significant privacy and security concerns. For that reason, the specification
 details measures browsers are required to take in order to fully support
 `getDisplayMedia()`.

* The specified options can't be used to limit the choices available
 to the user. Instead, they must be applied after the user chooses a source, in order
 to generate output that matches the options.
* The go-ahead permission to use `getDisplayMedia()` cannot be persisted
 for reuse. The user must be prompted for permission every time.
* Transient user activation is required. The user has to interact with the page or a UI element in order for this feature to work.
* Browsers are encouraged to provide a warning to users about sharing displays or
 windows that contain browsers, and to keep a close eye on what other content might be
 getting captured and shown to other users.
Examples
--------

 In the example below a `startCapture()` method is created, which initiates
 screen capture given a set of options specified by the `displayMediaOptions`
 parameter.

```js
const displayMediaOptions = {
  video: {
    displaySurface: "browser",
  },
  audio: {
    suppressLocalAudioPlayback: false,
  },
  preferCurrentTab: false,
  selfBrowserSurface: "exclude",
  systemAudio: "include",
  surfaceSwitching: "include",
  monitorTypeSurfaces: "include",
};

async function startCapture(displayMediaOptions) {
  let captureStream;

  try {
    captureStream =
      await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
  } catch (err) {
    console.error(`Error: ${err}`);
  }
  return captureStream;
}
```

 This uses `await` to asynchronously wait for `getDisplayMedia()`
 to resolve with a `MediaStream` which contains the display contents as
 requested by the specified options. The stream is then returned to the caller for use,
 perhaps for adding to a WebRTC call using `RTCPeerConnection.addTrack()` to
 add the video track from the stream.

**Note:** The Screen sharing controls demo provides a complete implementation that allows you to create a screen capture with your choice of `getDisplayMedia()` constraints and options.

Specifications
--------------

| Specification |
| --- |
| Screen Capture # dom-mediadevices-getdisplaymedia |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Screen Capture API
* Using the Screen Capture API
* Media Capture and Streams API
* WebRTC API
* `getUserMedia()`: Capturing media from a
 camera and/or microphone


MediaDevices: devicechange event - Web APIs

MediaDevices: devicechange event
================================

A `devicechange` event is sent to a `MediaDevices` instance whenever a media device such as a camera, microphone, or speaker is connected to or removed from the system.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("devicechange", (event) => {});

ondevicechange = (event) => {};
```

Event type
----------

A generic `Event`.

Example
-------

 In this example, we create a function called `updateDeviceList()`, which is
 called once when `MediaDevices.getUserMedia()` successfully obtains a
 stream, and then is called any time the device list changes. It displays in the browser
 window two lists: one of audio devices and one of video devices, with both the device's
 label (name) and whether it's an input or an output device. Because the example provides
 a handler for the `devicechange` event, the list is refreshed any time a
 media device is attached to or removed from the device running the sample.
```

<p>Click the start button below to begin the demonstration.</p>
<div id="startButton" class="button">Start</div>
<video id="video" width="160" height="120" autoplay></video><br />

<div class="left">
  <h2>Audio devices:</h2>
  <ul class="deviceList" id="audioList"></ul>
</div>
<div class="right">
  <h2>Video devices:</h2>
  <ul class="deviceList" id="videoList"></ul>
</div>

<output></output>
```

```
body {
  font:
    14px "Open Sans",
    "Arial",
    sans-serif;
}

video {
  margin-top: 20px;
  border: 1px solid black;
}

.button {
  cursor: pointer;
  width: 160px;
  border: 1px solid black;
  font-size: 16px;
  text-align: center;
  padding-top: 2px;
  padding-bottom: 4px;
  color: white;
  background-color: darkgreen;
}

h2 {
  margin-bottom: 4px;
}

.left {
  float: left;
  width: 48%;
  margin-right: 2%;
}

.right {
  float: right;
  width: 48%;
  margin-left: 2%;
}

.deviceList {
  border: 1px solid black;
  list-style-type: none;
  margin-top: 2px;
  padding: 6px;
}
```

```
// UI elements
const videoElement = document.querySelector("#video");
const logElement = document.querySelector("output");
const startButton = document.querySelector("#startButton");

function log(msg) {
  logElement.innerHTML += `${msg}<br>`;
}

startButton.addEventListener(
  "click",
  () => {
    const constraints = {
      video: {
        width: 160,
        height: 120,
        frameRate: 30,
      },
      audio: {
        sampleRate: 44100,
        sampleSize: 16,
        volume: 0.25,
      },
    };

    navigator.mediaDevices
      .getUserMedia(constraints)
      .then((stream) => {
        videoElement.srcObject = stream;
        updateDeviceList();
      })
      .catch((err) => {
        log(`${err.name}: ${err.message}`);
      });
  },
  false,
);
```

 We set up global variables that contain references to the `<ul>`
 elements that are used to list the audio and video devices:

```js
const audioList = document.getElementById("audioList");
const videoList = document.getElementById("videoList");
```

### Getting and drawing the device list

 Now let's take a look at `updateDeviceList()` itself. This method is called
 any time we want to fetch the current list of media devices and then update the
 displayed lists of audio and video devices using that information.

```js
function updateDeviceList() {
  navigator.mediaDevices.enumerateDevices().then((devices) => {
    audioList.innerHTML = "";
    videoList.innerHTML = "";

    devices.forEach((device) => {
      const elem = document.createElement("li");
      const [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i);

      elem.innerHTML = `<strong>${device.label}</strong> (${direction})`;
      if (type === "audio") {
        audioList.appendChild(elem);
      } else if (type === "video") {
        videoList.appendChild(elem);
      }
    });
  });
}
```

`updateDeviceList()` consists entirely of a call to the function
 `enumerateDevices()` on the
 `MediaDevices` object referenced in the
 `navigator.mediaDevices` property, as well as the code that's run when the
 `promise` returned by `enumerateDevices()` is fulfilled. The
 fulfillment handler is called when the device list is ready. The list is passed into the
 fulfillment handler as an array of `MediaDeviceInfo` objects, each
 describing one media input or output device.

 A `forEach()` loop is used to scan through all the
 devices. For each device, we create a new `<li>` object to be used to
 display it to the user.

 The line
 `let [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i);`
 deserves special notice. This uses destructuring assignment to assign the values of the first three items in the array returned by
 `String.match()` to the variables `kind`, `type`, and
 `direction`. We do this because the value of
 `MediaDeviceInfo.kind` is a single string that includes both the media type
 and the direction the media flows, such as "audioinput" or "videooutput". This line,
 then, pulls out the type ("audio" or "video") and direction ("input" or "output") so
 they can be used to construct the string displayed in the list.

 Once the string is assembled, containing the device's name in bold and the direction in
 parentheses, it's appended to the appropriate list by calling
 `appendChild()` on either `audioList` or
 `videoList`, as appropriate based on the device type.

### Handling device list changes

 We call `updateDeviceList()` in two places. The first is in the
 `getUserMedia()` promise's fulfillment
 handler, to initially fill out the list when the stream is opened. The second is in the
 event handler for this `devicechange` event:

```js
navigator.mediaDevices.ondevicechange = (event) => {
  updateDeviceList();
};
```

 With this code in place, each time the user plugs in a camera, microphone, or other
 media device, or turns one on or off, we call `updateDeviceList()` to redraw
 the list of connected devices.

### Result

Specifications
--------------

| Specification |
| --- |
| Media Capture and Streams # event-mediadevices-devicechange |
| Media Capture and Streams # dom-mediadevices-ondevicechange |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MediaDevices: selectAudioOutput() method - Web APIs

MediaDevices: selectAudioOutput() method
========================================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`MediaDevices.selectAudioOutput()`** method of the Audio Output Devices API prompts the user to select an audio output device, such as a speaker or headset. If the user selects a device, the method grants user permission to use the selected device as an audio output sink.

Following selection, if the device is available it can be enumerated using `MediaDevices.enumerateDevices()` and set as the audio output sink using `HTMLMediaElement.setSinkId()`.

On success, the returned `Promise` is resolved with a `MediaDeviceInfo` describing the selected device.

Syntax
------

```js
selectAudioOutput()
selectAudioOutput(options)
```

### Parameters

`options` Optional

An object that configures what device(s) may be offered in the user prompt.

`deviceId` Optional

 A string representing the ID of a single previously exposed/permitted device.
 If not set, a prompt with all available audio output devices will be displayed.

 The option is intended for applications that want to store a device id so that the same device can be used by default in future sessions.
 Note that the method may return a new ID for the same device, and that persisted ids *must be passed* through `selectAudioOutput()` successfully before they will work with `setSinkId()`.

**Note:** A user agent may choose to skip prompting the user if a specified non-null id was previously exposed to the user by `selectAudioOutput()` in an earlier session.
 In this case the user agent may simply resolve with this device id, or a new id for the same device if it has changed.
 If permission for the specified device was previously granted but has since been revoked, the user-agent might display all allowed devices, highlighting the one with the specified ID.

### Return value

A `Promise` that is fulfilled with a `MediaDeviceInfo` object that describes the audio output device selected by the user.

### Exceptions

`NotAllowedError` `DOMException`

Returned if a `speaker-selection` Permissions Policy is used to block use of audio outputs (in addition the popup for selecting an audio output won't be displayed), or the user closed the selection prompt without choosing a device.

`NotFoundError` `DOMException`

Returned if there are no available audio output devices.

`InvalidStateError` `DOMException`

Returned if there hasn't been a transient activation (you must trigger it from some kind of UI event).

Security requirements
---------------------

Access to the API is subject to the following constraints:

* The method must be called in a secure context.
* Transient user activation is required.
 The user has to interact with the page or a UI element for this feature to work.
* Access may be gated by the `speaker-selection` HTTP Permission Policy.

The permission status can be queried using the Permissions API method `navigator.permissions.query()`, passing a permission descriptor with the `speaker-selection` permission.

Examples
--------

 Here's an example of using `selectAudioOutput()`, within a function that is triggered by a button click.
 It outputs the selected device IDs and labels (if available) or an error message.

```js
document.querySelector("#myButton").addEventListener("click", () => {
  if (!navigator.mediaDevices.selectAudioOutput) {
    console.log("selectAudioOutput() not supported.");
    return;
  }

  // Display prompt and log selected device or error
  navigator.mediaDevices
    .selectAudioOutput()
    .then((device) => {
      console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
    })
    .catch((err) => {
      console.error(`${err.name}: ${err.message}`);
    });
});
```

On selection of an output this might produce:

```bash
audiooutput: Realtek Digital Output (Realtek(R) Audio) id = 0wE6fURSZ20H0N2NbxqgowQJLWbwo+5ablCVVJwRM3k=
```

Specifications
--------------

| Specification |
| --- |
| Audio Output Devices API # dom-mediadevices-selectaudiooutput |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement.setSinkId()`
* `HTMLMediaElement.sinkId`
* WebRTC - the introductory page to the API


MediaDevices: getSupportedConstraints() method - Web APIs

MediaDevices: getSupportedConstraints() method
==============================================

 The
 **`getSupportedConstraints()`**
 method of the `MediaDevices` interface returns an object based on the
 `MediaTrackSupportedConstraints` dictionary, whose member fields each
 specify one of the constrainable properties the user agent understands.

Syntax
------

```js
getSupportedConstraints()
```

### Parameters

None.

### Return value

 A new object based on the `MediaTrackSupportedConstraints` dictionary
 listing the constraints supported by the user agent. Because only constraints supported
 by the user agent are included in the list, each of these Boolean properties has the
 value `true`.

Examples
--------

This example outputs a list of the constraints supported by your browser.
```

<p>The following media constraints are supported by your browser:</p>

<ul id="constraintList"></ul>
```

```
body {
  font:
    15px Arial,
    sans-serif;
}
```

```js
const constraintList = document.querySelector("#constraintList");
const supportedConstraints = navigator.mediaDevices.getSupportedConstraints();

for (const constraint of Object.keys(supportedConstraints)) {
  const elem = document.createElement("li");
  elem.innerHTML = `<code>${constraint}</code>`;
  constraintList.appendChild(elem);
}
```

### Result

Specifications
--------------

| Specification |
| --- |
| Media Capture and Streams # dom-mediadevices-getsupportedconstraints |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MediaDevices: getUserMedia() method - Web APIs

MediaDevices: getUserMedia() method
===================================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

The **`getUserMedia()`** method of the `MediaDevices` interface prompts the user for permission to use a media input which produces a `MediaStream` with tracks containing the requested types of media.

That stream can include, for example, a video track (produced by either a hardware or virtual video source such as a camera, video recording device, screen sharing service, and so forth), an audio track (similarly, produced by a physical or virtual audio source like a microphone, A/D converter, or the like), and possibly other track types.

 It returns a `Promise` that resolves to a `MediaStream` object.
 If the user denies permission, or matching media is not available, then the promise is rejected with `NotAllowedError` or `NotFoundError` `DOMException` respectively.

**Note:** It's possible for the returned promise to *neither* resolve nor reject, as the user is not required to make a choice at all and may ignore the request.

Syntax
------

```js
getUserMedia(constraints)
```

### Parameters

`constraints`

 An object specifying the types of media to
 request, along with any requirements for each type.

 The `constraints` parameter is an object with two members: `video` and
 `audio`, describing the media types requested. Either or both must be
 specified. If the browser cannot find all media tracks with the specified types that
 meet the constraints given, then the returned promise is rejected with
 `NotFoundError` `DOMException`.

For both `video` and `audio`, its value is either a boolean or an object. The default value is `false`.

* If `true` is specified for a media type, the resulting stream is *required* to have that type of track in it. If one cannot be included for any reason, the returned promise will reject.
* If `false` is specified for a media type, the resulting stream *must not* have that type of track, or the returned promise will reject. Because both `video` and `audio` default to `false`, if the `constraints` object contains neither property or if it's not present at all, the returned promise will always reject.
* If an object is specified for a media type, the object is read as a `MediaTrackConstraints` dictionary.

### Return value

 A `Promise` whose fulfillment handler receives a `MediaStream`
 object when the requested media has successfully been obtained.

### Exceptions

`AbortError` `DOMException`

 Although the user and operating system both granted access to the hardware device,
 and no hardware issues occurred that would cause a `NotReadableError` `DOMException`, throw if some
 problem occurred which prevented the device from being used.

`InvalidStateError` `DOMException`

Thrown if current document is not fully active.

`NotAllowedError` `DOMException`

 Thrown if one or more of the requested source devices cannot be used at this time. This will
 happen if the browsing context is insecure (that is, the page was loaded using HTTP
 rather than HTTPS). It also happens if the user has specified that the current
 browsing instance is not permitted access to the device, the user has denied access
 for the current session, or the user has denied all access to user media devices
 globally. On browsers that support managing media permissions with Permissions Policy, this error is
 returned if Permissions Policy is not configured to allow access to the input source(s).

**Note:** Older versions of the specification used `SecurityError`
 for this instead; `SecurityError` has taken on a new meaning.

`NotFoundError` `DOMException`

Thrown if no media tracks of the type specified were found that satisfy the given constraints.

`NotReadableError` `DOMException`

 Thrown if, although the user granted permission to use the matching devices, a hardware error
 occurred at the operating system, browser, or Web page level which prevented access to
 the device.

`OverconstrainedError` `DOMException`

 Thrown if the specified constraints resulted in no candidate devices which met the criteria
 requested. The error is an object of type `OverconstrainedError`, and has a
 `constraint` property whose string value is the name of a constraint which
 was impossible to meet, and a `message` property containing a
 human-readable string explaining the problem.

**Note:** Because this error can occur even when the user has not yet granted
 permission to use the underlying device, it can potentially be used as a
 fingerprinting surface.

`SecurityError` `DOMException`

 Thrown if user media support is disabled on the `Document` on which
 `getUserMedia()` was called. The mechanism by which user media support is
 enabled and disabled is left up to the individual user agent.

`TypeError`

 Thrown if the list of constraints specified is empty, or has all constraints set to
 `false`. This can also happen if you try to call
 `getUserMedia()` in an insecure context, since
 `navigator.mediaDevices` is `undefined` in an insecure
 context.

Privacy and security
--------------------

 As an API that may involve significant privacy concerns, `getUserMedia()`'s
 specification lays out a wide array of privacy and security requirements that browsers
 are obligated to meet.

`getUserMedia()` is a powerful feature that can only be used in secure contexts; in insecure
 contexts, `navigator.mediaDevices` is `undefined`, preventing
 access to `getUserMedia()`. A secure context is, in short, a page loaded
 using HTTPS or the `file:///` URL scheme, or a page loaded from
 `localhost`.

 In addition, user permission is always required to access the user's audio and video
 inputs. Only a window's top-level document context for a valid origin can even request
 permission to use `getUserMedia()`, unless the top-level context expressly
 grants permission for a given `<iframe>` to do so using Permissions Policy. Otherwise, the user
 will never even be asked for permission to use the input devices.

 For additional details on these requirements and rules, how they are reflected in the
 context in which your code is running, and about how browsers manage user privacy and
 security issues, read on.

### User privacy

 As an API that may involve significant privacy concerns, `getUserMedia()` is
 held by the specification to very specific requirements for user notification and
 permission management. First, `getUserMedia()` must always get user
 permission before opening any media gathering input such as a webcam or microphone.
 Browsers may offer a once-per-domain permission feature, but they must ask at least the
 first time, and the user must specifically grant ongoing permission if they choose to do
 so.

 Of equal importance are the rules around notification. Browsers are required to display
 an indicator that shows that a camera or microphone is in use, above and beyond any
 hardware indicator that may exist. They must also show an indicator that permission has
 been granted to use a device for input, even if the device is not actively recording at
 the moment.

 For example in Firefox, the URL bar displays a pulsing red icon to indicate that
 recording is underway. The icon is gray if the permission is in place but recording is
 not currently underway. The device's physical light is used to indicate whether or not
 recording is currently active. If you've muted your camera (so-called "facemuting"),
 your camera's activity light goes out to indicate that the camera is not actively
 recording you, without discarding the permission to resume using the camera once muting
 is over.

### Security

There are a number of ways security management and controls in a user agent can cause `getUserMedia()` to return a security-related error.

#### Permissions Policy

 The two Permissions Policy directives that apply to `getUserMedia()` are `camera`
 and `microphone`.

 For example, this HTTP header will enable use of a camera by the document
 and any embedded `<iframe>` elements that are loaded from the same
 origin:

```http
Permissions-Policy: camera=(self)
```

 This will request access to the microphone for the current origin and the specific
 origin `https://developer.mozilla.org`:

```http
Permissions-Policy: microphone=(self "https://developer.mozilla.org")
```

 If you're using `getUserMedia()` within an `<iframe>`, you
 can request permission just for that frame, which is clearly more secure than requesting
 a more general permission. Here, indicate we need the ability to use both camera and
 microphone:

```html
<iframe src="https://mycode.example.net/etc" allow="camera; microphone">
</iframe>
```

#### Encryption based security

 The `getUserMedia()` method is only available in secure contexts. A secure context
 is one the browser is reasonably confident contains a document which was loaded
 securely, using HTTPS/TLS, and has limited exposure to insecure contexts. If a document
 isn't loaded in a secure context, the `navigator.mediaDevices` property is
 `undefined`, making access to `getUserMedia()` impossible.

 Attempting to access `getUserMedia()` in this situation will result in a
 `TypeError`.

#### Document source security

 Because of the obvious security concern associated with `getUserMedia()` if
 used unexpectedly or without security being carefully managed, it can only be used in
 secure contexts. There are a number of insecure ways to load a document that might, in
 turn, attempt to call `getUserMedia()`. The following are examples of
 situations in which `getUserMedia()` is not permitted to be called:

* A document loaded into a sandboxed `<iframe>` element cannot call
 `getUserMedia()` unless the `<iframe>` has its
 `sandbox` attribute set to `allow-same-origin`.
* A document loaded using a `data://` or `blob://` URL which has
 no origin (such as when one of these URLs is typed by the user into the address bar)
 cannot call `getUserMedia()`. These kinds of URLs loaded from JavaScript
 code inherit the script's permissions.
* Any other situation in which there is no origin, such as when the
 `srcdoc` attribute is used to specify the contents of a
 frame.
Examples
--------

### Using getUserMedia()

Generally, you will access the `MediaDevices` singleton object using `navigator.mediaDevices`, like this:

```js
async function getMedia(constraints) {
  let stream = null;

  try {
    stream = await navigator.mediaDevices.getUserMedia(constraints);
    /\* use the stream \*/
  } catch (err) {
    /\* handle the error \*/
  }
}
```

Similarly, using the raw promises directly, the code looks like this:

```js
navigator.mediaDevices
  .getUserMedia(constraints)
  .then((stream) => {
    /\* use the stream \*/
  })
  .catch((err) => {
    /\* handle the error \*/
  });
```

**Note:** If the current document isn't loaded securely,
 `navigator.mediaDevices` will be `undefined`, and you cannot use
 `getUserMedia()`. See Security for more information on this and
 other security issues related to using `getUserMedia()`.

Below are some examples of the `constraints` parameter.

The following requests both audio and video without any specific requirements:

```js
getUserMedia({
  audio: true,
  video: true,
});
```

 While information about a user's cameras and microphones are inaccessible for
 privacy reasons, an application can request the camera and microphone capabilities
 it needs and wants, using additional constraints. The following expresses a
 preference for 1280x720 camera resolution:

```js
getUserMedia({
  audio: true,
  video: { width: 1280, height: 720 },
});
```

 The browser will try to honor this, but may return other
 resolutions if an exact match is not available, or the user overrides it.

 To *require* a capability, use the keywords `min`,
 `max`, or `exact` (a.k.a. `min === max`). The
 following demands a minimum resolution of 1280x720:

```js
getUserMedia({
  audio: true,
  video: {
    width: { min: 1280 },
    height: { min: 720 },
  },
});
```

 If no camera exists with this resolution or higher, then the returned promise will
 be rejected with `OverconstrainedError`, and the user will not be
 prompted.

 The reason for the difference in behavior is that the keywords `min`,
 `max`, and `exact` are inherently mandatory — whereas plain
 values and a keyword called `ideal` are not. Here's a full example:

```js
getUserMedia({
  audio: true,
  video: {
    width: { min: 1024, ideal: 1280, max: 1920 },
    height: { min: 576, ideal: 720, max: 1080 },
  },
});
```

 An `ideal` value, when used, has gravity — which means that the browser
 will try to find the setting (and camera, if you have more than one), with the
 smallest fitness distance from the ideal values given.

 Plain values are inherently ideal, which means that the first of our resolution
 examples above could have been written like this:

```js
getUserMedia({
  audio: true,
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 },
  },
});
```

 Not all constraints are numbers. For example, on mobile devices, the following will
 prefer the front camera (if one is available) over the rear one:

```js
getUserMedia({
  audio: true,
  video: { facingMode: "user" },
});
```

To *require* the rear camera, use:

```js
getUserMedia({
  audio: true,
  video: {
    facingMode: { exact: "environment" },
  },
});
```

 Another non-number constraint is the `deviceId` constraint. If you have
 a `deviceId` from `mediaDevices.enumerateDevices()`, you can
 use it to request a specific device:

```js
getUserMedia({
  video: {
    deviceId: myPreferredCameraDeviceId,
  },
});
```

 The above will return the camera you requested, or a different camera if that
 specific camera is no longer available. Again, to *require* the specific
 camera, you would use:

```js
getUserMedia({
  video: {
    deviceId: {
      exact: myExactCameraOrBustDeviceId,
    },
  },
});
```

### Width and height

 This example gives a preference for camera resolution, and assigns the resulting
 `MediaStream` object to a video element.

```js
// Prefer camera resolution nearest to 1280x720.
const constraints = {
  audio: true,
  video: { width: 1280, height: 720 },
};

navigator.mediaDevices
  .getUserMedia(constraints)
  .then((mediaStream) => {
    const video = document.querySelector("video");
    video.srcObject = mediaStream;
    video.onloadedmetadata = () => {
      video.play();
    };
  })
  .catch((err) => {
    // always check for errors at the end.
    console.error(`${err.name}: ${err.message}`);
  });
```

### Frame rate

 Lower frame-rates may be desirable in some cases, like WebRTC transmissions with
 bandwidth restrictions.

```js
const constraints = {
  video: { frameRate: { ideal: 10, max: 15 } },
};
```

### Front and back camera

On mobile phones.

```js
let front = false;
document.getElementById("flip-button").onclick = () => {
  front = !front;
};

const constraints = {
  video: { facingMode: front ? "user" : "environment" },
};
```

**Note:** In certain cases, it may be necessary to release the current camera facing mode before you can switch to a different one. To ensure the camera switch, it is advisable to free up the media resources by invoking the "stop()" method on the track before requesting a different facing mode.

Specifications
--------------

| Specification |
| --- |
| Media Capture and Streams # dom-mediadevices-getusermedia |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* The older `Navigator.getUserMedia()` legacy API
* `MediaDevices.enumerateDevices()`: Listing available media devices
* WebRTC API
* Media Capture and Streams API
* Screen Capture API: Capturing screen contents as a `MediaStream`
* `MediaDevices.getDisplayMedia()`: Getting a stream containing screen contents
* Taking webcam photos: A tutorial on using `getUserMedia()` to take still photos rather than video


Using channel messaging - Web APIs

Using channel messaging
=======================

The Channel Messaging API allows two separate scripts running in different browsing contexts attached to the same document (e.g., two `<iframe>` elements, the main document and a single `<iframe>`, or two documents via a `SharedWorker`) to communicate directly, passing messages between each other through two-way channels (or pipes) with a port at each end.

In this article we'll explore the basics of using this technology.

**Note:** This feature is available in Web Workers

Use cases
---------

Channel messaging is mainly useful in cases where you've got a social site that embeds capabilities from other sites into its main interface via iframes, such as games, address books or an audio player with personalized music choices. When these act as standalone units, things are OK, but the difficulty comes when you want interaction between the main site and the `<iframe>` elements, or between different `<iframe>` elements. For example, what if you wanted to add a contact to the address book from the main site, add high scores from your game to your main profile, or add new background music choices from the audio player to the game? Such things are not so easy using conventional web technology, because of the security models the web uses. You have to think about whether the origins trust each other, and how the messages are passed.

Message channels on the other hand can provide a secure channel that allows you to pass data between different browsing contexts.

**Note:** For more information and ideas, the Ports as the basis of an object-capability model on the Web section of the spec is a useful read.

Simple examples
---------------

To get you started, we have published a couple of demos on GitHub. First, check our channel messaging basic demo (run it live too), which shows a really simple single message transfer between a page and an embedded `<iframe>`.

Second, have a look at our multimessaging demo (run this live), which shows a slightly more complex setup that can send multiple messages between the main page and an IFrame.

We'll be focusing on the latter example in this article, which looks like:

![Demo with "Hello this is my demo" sent as five separate messages. The messages are displayed as a bulleted list.](/en-US/docs/Web/API/Channel_Messaging_API/Using_channel_messaging/channel-messaging-demo.png)

Creating the channel
--------------------

In the main page of the demo, we have a simple form with a text input for entering messages to be sent to an `<iframe>`. We also have a paragraph which we will use later on to display confirmation messages that we will receive back from the `<iframe>`.

```js
const input = document.getElementById("message-input");
const output = document.getElementById("message-output");
const button = document.querySelector("button");
const iframe = document.querySelector("iframe");

const channel = new MessageChannel();
const port1 = channel.port1;

// Wait for the iframe to load
iframe.addEventListener("load", onLoad);

function onLoad() {
  // Listen for button clicks
  button.addEventListener("click", onClick);

  // Listen for messages on port1
  port1.onmessage = onMessage;

  // Transfer port2 to the iframe
  iframe.contentWindow.postMessage("init", "\*", [channel.port2]);
}

// Post a message on port1 when the button is clicked
function onClick(e) {
  e.preventDefault();
  port1.postMessage(input.value);
}

// Handle messages received on port1
function onMessage(e) {
  output.innerHTML = e.data;
  input.value = "";
}
```

We start off by creating a new message channel by using the `MessageChannel()` constructor.

When the IFrame has loaded, we register an `onclick` handler for our button and an `onmessage` handler for `MessageChannel.port1`. Finally we transfer `MessageChannel.port2` to the IFrame using the `window.postMessage` method.

Let's explore how the `iframe.contentWindow.postMessage` line works in more detail. It takes three arguments:

1. The message being sent. For this initial port transferring this message could be an empty string but in this example it is set to `'init'`.
2. The origin the message is to be sent to. `*` means "any origin".
3. An object, the ownership of which is transferred to the receiving browsing context. In this case, we are transferring `MessageChannel.port2` to the IFrame, so it can be used to communicate with the main page.

When our button is clicked, we prevent the form from submitting as normal and then send the value entered in our text input to the IFrame via the `MessageChannel`.

Receiving the port and message in the IFrame
--------------------------------------------

In the `<iframe>` elements, we have the following JavaScript:

```js
const list = document.querySelector("ul");
let port2;

// Listen for the initial port transfer message
window.addEventListener("message", initPort);

// Setup the transferred port
function initPort(e) {
  port2 = e.ports[0];
  port2.onmessage = onMessage;
}

// Handle messages received on port2
function onMessage(e) {
  const listItem = document.createElement("li");
  listItem.textContent = e.data;
  list.appendChild(listItem);
  port2.postMessage(`Message received by IFrame: "${e.data}"`);
}
```

When the initial message is received from the main page via the `window.postMessage` method, we run the `initPort` function. This saves the transferred port and registers an `onmessage` handler that will be called each time a message is passed through our `MessageChannel`.

When a message is received from the main page, we create a list item and insert it in the unordered list, setting the `textContent` of the list item equal to the event's `data` attribute (this contains the actual message).

Next, we post a confirmation message back to the main page via the message channel by calling `MessagePort.postMessage` on `MessageChannel.port2` that was initially transferred to the iframe.

Receiving the confirmation in the main page
-------------------------------------------

Returning to the main page, let's now look at the `onmessage` handler function.

```js
// Handle messages received on port1
function onMessage(e) {
  output.innerHTML = e.data;
  input.value = "";
}
```

When a message is received back from the IFrame confirming that the original message was received successfully, this outputs the confirmation to a paragraph and empties the text input ready for the next message to be sent.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # message-channels |
| HTML Standard # message-ports |

Browser compatibility
---------------------

### api.MessageChannel

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.MessagePort

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Channel Messaging API
* Web Workers API
* Broadcast Channel API