This document proposes a set of HTML elements, <usermedia>, <camera>, and <microphone>, that mean to provide user-friendly and secure access to a {{MediaStream}}, handling the required premissions in the process.

This is a delta specification, meant to eventually be included in [[mediacapture-streams]] or [[mediacapture-extensions]].

This is a delta specification, meant to eventually be included in [[mediacapture-streams]] or [[mediacapture-extensions]]. It currently contains only the differences from this spec.

The <usermedia>, <camera>, and <microphone> media capture HTML elements

The <usermedia>, <camera>, and <microphone> HTML elements are [[HTML]] elements that can mediate access to a {{MediaStream}}, including handling the required [=permission/prompts=] for [=powerful features=].

These three elements cover three different use cases and allow for use case specific user interfaces in the [=user agent=]. Their content attributes and IDL are mostly the same.

The <usermedia> element uses the following DOM interface:

      [Exposed=Window]
      interface HTMLUserMediaElement : HTMLElement {
        [HTMLConstructor] constructor();

        readonly attribute MediaStream? stream;
        undefined setConstraints(MediaStreamConstraints constraints);
        readonly attribute DOMException? error;
      };
      HTMLUserMediaElement includes ActivationBlockersMixin;
    

The <camera> and <microphone> DOM interfaces are almost the same. The <camera> element uses the following DOM interface:

      [Exposed=Window]
      interface HTMLCameraElement : HTMLElement {
        [HTMLConstructor] constructor();

        readonly attribute MediaStream? stream;
        undefined setConstraints(MediaStreamConstraints constraints);
        readonly attribute DOMException? error;
      };
      HTMLCameraElement includes ActivationBlockersMixin;
    

The <microphone> element uses the following DOM interface:

      [Exposed=Window]
      interface HTMLMicrophoneElement : HTMLElement {
        [HTMLConstructor] constructor();

        readonly attribute MediaStream? stream;
        undefined setConstraints(MediaStreamConstraints constraints);
        readonly attribute DOMException? error;
      };
      HTMLMicrophoneElement includes ActivationBlockersMixin;
    

The <usermedia>, <camera>, and <microphone> elements all use the following internal slot:

The <usermedia>, <camera>, and <microphone> elements belong to the [=flow content=], [=phrasing content=], [=interactive content=], and [=palpable content=] categories. They can be used in contexts where [=phrasing content=] is expected. Their content, if any, are their fallback content. They use the {{ActivationBlockersMixin}} from [[geolocation-element]], to provide protection against programmatic activation.

The <usermedia>, <camera>, and <microphone> elements all support the following content attributes:

global attributes
— all global content attributes.
isValid
invalidReason
onvalidationstatuschange
— content attributes from {{ActivationBlockersMixin}}

Algorithms

The {{HTMLUserMediaElement}}, {{HTMLCameraElement}}, and {{HTMLMicrophoneElement}} all use the same constructor steps. Their {{HTMLUserMediaElement/constructor()}} steps are:

  1. Run {{ActivationBlockersMixin}}'s [=ActivationBlockersMixin/initialization steps=].
  2. Initialize {{HTMLUserMediaElement/[[stream]]}} to null.
  3. Initialize {{HTMLUserMediaElement/[[error]]}} to null.
  4. Initialize {{HTMLUserMediaElement/[[constraints]]}} to [=this=]'s [=HTMLUserMediaElement/default constraints=].

The <usermedia> element's [=insertion steps=] are:

  1. Run {{ActivationBlockersMixin}}'s [=ActivationBlockersMixin/insertion steps=].

The <usermedia> element's [=removing steps=] are:

  1. Run {{ActivationBlockersMixin}}'s [=ActivationBlockersMixin/removing steps=].

The {{HTMLUserMediaElement/stream}} getter steps are:

  1. Return {{HTMLUserMediaElement/[[stream]]}}.

The {{HTMLUserMediaElement/setConstraints()}} steps for an |element| and a parameter |constraints| steps:

  1. Set {{HTMLUserMediaElement/[[constraints]]}} to the result of [=HTMLUserMediaElement/constraint filter=] for |element| and |constraints|.

The {{HTMLUserMediaElement/error}} getter steps are:

  1. Return {{HTMLUserMediaElement/[[error]]}}.

The <usermedia>, <camera>, and <microphone> permission name are:

Element type Value
<usermedia> The [=string/concatenate|concatentation=] of « [=/"camera"=], " ", [=/"microphone"=] ».
<camera> [=/"camera"=]
<microphone> [=/"microphone"=]

The <usermedia>, <camera>, and <microphone> default constraints are:

Element type Value
<usermedia> «[ {{MediaStreamConstraints/video}} → true, {{MediaStreamConstraints/audio}} → true ]»
<camera> «[ {{MediaStreamConstraints/video}} → true, {{MediaStreamConstraints/audio}} → false ]»
<microphone> «[ {{MediaStreamConstraints/video}} → false, {{MediaStreamConstraints/audio}} → true ]»

The <usermedia> |element|'s [=EventTarget/activation behavior=] is:

  1. If |element|.{{ActivationBlockersMixin/isValid}} is false, then return.
  2. If {{HTMLUserMediaElement/[[stream]]}} is null, run [=HTMLUserMediaElement/activation initial=] steps.
  3. Otherwise, run [=HTMLUserMediaElement/activation second=] steps.

The activation initial steps are:

  1. [=Assert=]: |element|.{{ActivationBlockersMixin/isValid}}.
  2. [=Assert=]: {{HTMLUserMediaElement/[[stream]]}} is null.
  3. Let |permissionName| be |element|'s [=permission name=].
  4. Let |descriptor| be a new {{PermissionDescriptor}} with value «[ {{PermissionDescriptor/name}} → |permissionName| ]».
  5. Let |permissionState| be the result of [=request permission to use=] the [=powerful features=] described by |descriptor| with allowMultiple set to false.
  6. If |permissionState| is not {{PermissionState/"granted"}}:
    1. Set {{HTMLUserMediaElement/[[stream]]}} to null.
    2. Set {{HTMLUserMediaElement/[[error]]}} to null.
    3. Return.
  7. Let |contraints| be {{HTMLUserMediaElement/[[constraints]]}}.
  8. Let |mediaPromise| be the result of calling {{MediaDevices/getUserMedia()}} with |constraints| as its first argument.
  9. [=promise/React=] to |mediaPromise|:
    1. If |mediaPromise| was fulfilled with value |v|:
      1. [=Assert=]: |v| is a {{MediaStream}}.
      2. Set {{HTMLUserMediaElement/[[stream]]}} to |v|.
      3. Set {{HTMLUserMediaElement/[[error]]}} to null.
    2. else:
      1. [=Assert=]: |mediaPromise| was rejected with reason |r|.
      2. [=Assert=]: |r| is a |DOMException|.
      3. Set {{HTMLUserMediaElement/[[stream]]}} to null.
      4. Set {{HTMLUserMediaElement/[[error]]}} to |r|.

The activation second steps are:

  1. [=Assert=]: |element|.{{ActivationBlockersMixin/isValid}}.
  2. [=Assert=]: {{HTMLUserMediaElement/[[stream]]}} is a {{MediaStream}}.
  3. TODO: We ought to do something here, too.

The constraint filter steps for an |element| and {{MediaStreamConstraints}} |constraints| are:

  1. Let |result| be a new [=dictionary=].
  2. If |element| is a {{HTMLUserMediaElement}}, set |result| to «[ {{MediaStreamConstraints/audio}} → |constraints|[{{MediaStreamConstraints/audio}}], {{MediaStreamConstraints/video}} → |constraints|[{{MediaStreamConstraints/video}}] ]».
  3. Otherwise, if |element| is a {{HTMLMicrophoneElement}}, set |result| to «[ {{MediaStreamConstraints/audio}} → |constraints|[{{MediaStreamConstraints/audio}}], {{MediaStreamConstraints/video}} → false ]».
  4. Otherwise, if |element| is a {{HTMLCameraElement}}, set |result| to «[ {{MediaStreamConstraints/audio}} → false, {{MediaStreamConstraints/video}} → |constraints|[{{MediaStreamConstraints/video}}] ]».
  5. TODO: |results| should have additional filtering to support a reasonable, easy-to-use subset of all the constraints allowed for the getUserMedia call.
  6. Return |result|.

<usermedia> legacy support.

To ease transition from the current <usermedia> element in Chrome, we support a limited form of the {{HTMLUserMediaElementLegacyMixin/type}} attribute, with values for `audio`, `video`, or both. If this attribute is set, it modifies the behaviour of the <usermedia> element to match the behaviour of any of the elements discussed here. This is a hold-over from the original <permission> element design. It is expected that this mixin will not be included in the final standard.

      interface mixin HTMLUserMediaElementLegacyMixin {
        attribute DOMString type;
        boolean isTypeSupported(DOMString type);
      };
      HTMLUserMediaElement includes HTMLUserMediaElementLegacyMixin;
      

The {{HTMLUserMediaElementLegacyMixin/type}} IDL attribute reflects the `type` content attribute. Depending on {{HTMLUserMediaElementLegacyMixin/type}}, the <usermedia> element changes behaviour:

`"audio video"`
`"video audio"`
— behaves like a regular <usermedia> element.
`"audio"`
— behaves like an <microphone> element.
`"video"`
— behaves like a <camera> element.
all other values
— behaves like an {{HTMLUnknownElement}}.

The {{HTMLUserMediaElementLegacyMixin/isTypeSupported()}} method can be used to query whether a given type is supported by this element. It will return true if the input string is one of `"audio video"`, `"video audio"`, `"audio"`, or `"video"`, and false in all other cases.