MediaStream Recording

Editor’s Draft,

This version:
https://w3c.github.io/mediacapture-record/
Feedback:
public-media-capture@w3.org with subject line “[mediastream-recording] … message topic …” (archives)
Editor:
(Google Inc.)
Former Editors:
Jim Barnett (Genesis)
(Microsoft Corp.)
Participate:
Mailing list
GitHub repo (new issue, open issues)
Implementation:
Can I use Media Recording?
Chromium Encode Acceleration Support

Abstract

This document defines a recording API for use with MediaStreams.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

If you wish to make comments regarding this document, please file an issue on the specification repository or send them to subscribe, archives).

This document was produced by the Device and Sensors Working Group and the Web Real-Time Communications Working Group.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 September 2015 W3C Process Document.

1. Overview

This API attempts to make basic recording very simple, while still allowing for more complex use cases. In the simplest case, the application instantiates a MediaRecorder object, calls start() and then calls stop() or waits for the MediaStreamTrack(s) to be ended. The contents of the recording will be made available in the platform’s default encoding via the ondataavailable event. Functions are available to query the platform’s available set of encodings, and to select the desired ones if the author wishes. The application can also choose how much data it wants to receive at one time. By default a Blob containing the entire recording is returned when the recording finishes. However the application can choose to receive smaller buffers of data at regular intervals.

2. Media Recorder API

[Constructor(MediaStream stream, optional MediaRecorderOptions options)]
interface MediaRecorder : EventTarget {
  readonly attribute MediaStream stream;
  readonly attribute DOMString mimeType;
  readonly attribute RecordingState state;
  attribute EventHandler onstart;
  attribute EventHandler onstop;
  attribute EventHandler ondataavailable;
  attribute EventHandler onpause;
  attribute EventHandler onresume;
  attribute EventHandler onerror;
  readonly attribute unsigned long videoBitsPerSecond;
  readonly attribute unsigned long audioBitsPerSecond;

  void start(optional long timeslice);
  void stop();
  void pause();
  void resume();
  void requestData();

  static boolean isTypeSupported(DOMString type);
};

2.1. Constructors

MediaRecorder(MediaStream stream, optional MediaRecorderOptions options)
Parameter Type Nullable Optional Description
stream MediaStream The MediaStream to be recorded. This will be the value of the stream attribute.
options MediaRecorderOptions A dictionary of options to for the UA instructing how the recording will take part. options.mimeType, if present, will become the value of mimeType attribute.

2.2. Attributes

stream, of type MediaStream, readonly
The MediaStream to be recorded.
mimeType, of type DOMString, readonly
The MIME type [RFC2046] that has been selected as the container for recording. This entry includes all the parameters to the base mimeType. The UA should be able to play back any of the MIME types it supports for recording. For example, it should be able to display a video recording in the HTML <video> tag. The default value for this property is platform-specific.
mimeType specifies the media type and container format for the recording via a type/subtype combination, with the codecs and/or profiles parameters [RFC6381] specified where ambiguity might arise. Individual codecs might have further optional specific parameters.
state, of type RecordingState, readonly
The current state of the MediaRecorder object. When the MediaRecorder is created, the UA MUST set this attribute to inactive.
onstart, of type EventHandler
Called to handle the start event.
onstop, of type EventHandler
Called to handle the stop event.
ondataavailable, of type EventHandler
Called to handle the dataavailable event. The Blob of recorded data is contained in this event and can be accessed via its data attribute.
onpause, of type EventHandler
Called to handle the pause event.
onresume, of type EventHandler
Called to handle the resume event.
onerror, of type EventHandler
Called to handle a MediaRecorderErrorEvent.
videoBitsPerSecond, of type unsigned long, readonly
The value of the Video encoding target bit rate that was passed to the Platform (potentially truncated, rounded, etc), or the calculated one if the user has specified bitsPerSecond.
audioBitsPerSecond, of type unsigned long, readonly
The value of the Audio encoding target bit rate that was passed to the Platform (potentially truncated, rounded, etc), or the calculated one if the user has specified bitsPerSecond.

2.3. Methods

start(optional long timeslice)
When a MediaRecorder object’s start() method is invoked, the UA MUST run the following steps:
  1. Let target be the MediaRecorder context object.
  2. Let timeslice be the method’s first argument, if provided, or undefined.
  3. If state is not inactive, throw an InvalidStateError DOMException and abort these steps.
  4. If the stream's isolation properties disallow access from this MediaRecorder, throw a SecurityError DOMException and abort these steps.
  5. Set state to recording, and run the following steps in parallel:
    1. Once media becomes available from one or more of the stream's tracks, start gathering the data into a Blob blob and queue a task, using the DOM manipulation task source, to fire an event named start at target.
    2. If at any point the stream's isolation properties change so that MediaRecorder is no longer allowed access to it, the UA MUST immediately stop gathering data, discard any data that it has gathered, and queue a task, using the DOM manipulation task source, that runs the following steps:
      1. Set state to inactive.
      2. Fire an error event named SecurityError at target.
      3. Fire a blob event named dataavailable at target with blob.
      4. Fire an event named stop at target.
    3. If the UA at any point is unable to continue gathering data for reasons other than isolation properties, it MUST stop gathering data, and queue a task, using the DOM manipulation task source, that runs the following steps:
      1. Set state to inactive.
      2. Fire an error event named UnknownError at target.
      3. Fire a blob event named dataavailable at target with blob.
      4. Fire an event named stop at target.
    4. If timeslice is not undefined, then once a minimum of timeslice milliseconds of data have been collected, or some minimum time slice imposed by the UA, whichever is greater, start gathering data into a new Blob blob, and queue a task, using the DOM manipulation task source, that fires a blob event named dataavailable at target with blob.

      Note that an undefined value of timeslice will be understood as the largest long value.

    5. If all recorded tracks become ended, then stop gathering data, and queue a task, using the DOM manipulation task source, that runs the following steps:
      1. Set state to inactive.
      2. Fire a blob event named dataavailable at target with blob.
      3. Fire an event named stop at target.
  6. return undefined.

Note that stop(), requestData(), and pause() also affect the recording behavior.

The UA MUST record stream in such a way that the original Tracks can be retrieved at playback time. When multiple Blobs are returned (because of timeslice or requestData()), the individual Blobs need not be playable, but the combination of all the Blobs from a completed recording MUST be playable.

If any Track within the MediaStream is muted or not enabled at any time, the UA will only record black frames or silence since that is the content produced by the Track.

Parameter Type Nullable Optional Description
timeslice long The minimum number of milliseconds of data to return in a single Blob.
stop()
When a MediaRecorder object’s stop() method is invoked, the UA MUST run the following steps:
  1. If state is inactive throw an InvalidStateError DOMException and terminate these steps. Otherwise the UA MUST queue a task, using the DOM manipulation task source, that runs the following steps:
    1. Set state to inactive and stop gathering data.
    2. Let blob be the Blob of collected data so far and let target be the MediaRecorder context object, then fire a blob event named dataavailable at target with blob.
    3. Fire an event named stop at target.
  2. return undefined.
pause()
When a MediaRecorder object’s pause() method is invoked, the UA MUST run the following steps:
  1. If state is inactive throw an InvalidStateError DOMException and terminate these steps. Otherwise the UA MUST queue a task, using the DOM manipulation task source, that runs the following steps:
    1. Set state to paused.
    2. Stop gathering data into blob (but keep it available so that recording can be resumed in the future).
    3. Let target be the MediaRecorder context object. Fire an event named pause at target.
  2. return undefined.
resume()
When a MediaRecorder object’s resume() method is invoked, the UA MUST run the following steps:
  1. If state is inactive throw an InvalidStateError DOMException and terminate these steps. Otherwise the UA MUST queue a task, using the DOM manipulation task source, that runs the following steps:
    1. Set state to recording.
    2. Resume (or continue) gathering data into the current blob.
    3. Let target be the MediaRecorder context object. Fire an event named resume at target.
  2. return undefined.
requestData()
When a MediaRecorder object’s requestData() method is invoked, the UA MUST run the following steps:
  1. If state is inactive throw an InvalidStateError DOMException and terminate these steps. Otherwise the UA MUST queue a task, using the DOM manipulation task source, that runs the following steps:
    1. Let blob be the Blob of collected data so far and let target be the MediaRecorder context object, then fire a blob event named dataavailable at target with blob. (Note that blob will be empty if no data has been gathered yet.)
    2. Create a new Blob and gather subsequent data into it.
  2. return undefined.
isTypeSupported(DOMString type)
Check to see whether a MediaRecorder can record in a specified MIME type. If true is returned from this method, it only indicates that the MediaRecorder implementation is capable of recording Blob objects for the specified MIME type. Recording may still fail if sufficient resources are not available to support the concrete media encoding. When this method is invoked, the User Agent must run the following steps:
  1. If type is an empty string, then return true (note that this case is essentially equivalent to leaving up to the UA the choice of container and codecs on constructor).
  2. If type does not contain a valid MIME type string, then return false.
  3. If type contains a media type or media subtype that the MediaRecorder does not support, then return false.
  4. If type contains a media container that the MediaRecorder does not support, then return false.
  5. If type contains a codec that the MediaRecorder does not support, then return false.
  6. If the MediaRecorder does not support the specified combination of media type/subtype, codecs and container then return false.
  7. Return true.
Parameter Type Nullable Optional Description
type DOMString A MIME Type, including parameters when needed, specifying a container and/or codec formats for recording.

2.4. Data handling

To fire a blob event with a Blob blob means to fire an event at target using a BlobEvent with its data attribute initialized to blob.

Usually blob will be the data gathered by the UA after the last transition to recording state.

2.5. MediaRecorderOptions

dictionary MediaRecorderOptions {
  DOMString mimeType;
  unsigned long audioBitsPerSecond;
  unsigned long videoBitsPerSecond;
  unsigned long bitsPerSecond;
};

2.5.1. Members

mimeType, of type DOMString
The container and codec format(s) [RFC2046] for the recording, which may include any parameters that are defined for the format. If the UA does not support the format or any of the parameters specified, it MUST throw a NotSupportedError DOMException. If this paramater is not specified, the UA will use a platform-specific default format. The container format, whether passed in to the constructor or defaulted, will be used as the value of the mimeType attribute.
mimeType specifies the media type and container format for the recording via a type/subtype combination, with the codecs and/or profiles parameters [RFC6381] specified where ambiguity might arise. Individual codecs might have further optional or mandatory specific parameters.
audioBitsPerSecond, of type unsigned long
Aggregate target bits per second for encoding of the Audio track(s), if any. This is a hint for the encoder and the value might be surpassed, not achieved, or only be achieved over a long period of time.
videoBitsPerSecond, of type unsigned long
Aggregate target bits per second for encoding of the Video track(s), if any. This is a hint for the encoder and the value might be surpassed, not achieved, or only be achieved over a long period of time.
bitsPerSecond, of type unsigned long
Aggregate target bits per second for encoding of all Video and Audio Track(s) present. This parameter overrides either audioBitsPerSecond or videoBitsPerSecond if present, and might be distributed among the present track encoders as the UA sees fit. This parameter is a hint for the encoder(s) and the total value might be surpassed, not achieved, or only be achieved over a long period of time.

2.6. RecordingState

enum RecordingState {
  "inactive",
  "recording",
  "paused"
};

2.6.1. Values

inactive
Recording is not occuring: Either it has not been started or it has been stopped.
recording
Recording has been started and the UA is capturing data.
paused
Recording has been started, then paused, and not yet stopped or resumed.

3. Blob Event

[Constructor(DOMString type, BlobEventInit eventInitDict)]
interface BlobEvent : Event {
  [SameObject] readonly attribute Blob data;
  readonly attribute DOMHighResTimeStamp timecode;
};

3.1. Constructors

BlobEvent(DOMString type, BlobEventInit eventInitDict)

3.2. Attributes

data, of type Blob, readonly
The encoded Blob whose type attribute indicates the encoding of the blob data.
timecode, of type DOMHighResTimeStamp, readonly
The difference between the timestamp of the first chunk in data and the timestamp of the first chunk in the first BlobEvent produced by this recorder. Note that the timecode in the first produced BlobEvent does not need to be zero.

3.3. BlobEventInit

dictionary BlobEventInit {
  required Blob data;
  DOMHighResTimeStamp timecode;
};

3.3.1. Members

data, of type Blob
A Blob object containing the data to deliver via BlobEvent.
timecode, of type DOMHighResTimeStamp
The timecode to be used in initializing BlobEvent.

4. Error handling

4.1. General principles

This section is non-normative.

The UA will throw a DOMException when the error can be detected at the time that the call is made. In all other cases the UA will fire an event named MediaRecorderErrorEvent. If recording has been started and not yet stopped when the error occurs, let blob be the Blob of collected data so far; after raising the error, the UA will fire a dataavailable event with blob; immediately after the UA will then fire an event named stop. The UA may set platform-specific limits, such as those for the minimum and maximum Blob size that it will support, or the number of MediaStreamTracks it will record at once. It will signal a fatal error if these limits are exceeded.

4.2. MediaRecorderErrorEvent

The MediaRecorderErrorEvent interface is defined for cases when an event is raised that was caused by an error.

To fire an error event named e with a DOMException named error means that an event with the name e, which does not bubble (except where otherwise stated) and is not cancelable (except where otherwise stated), and which uses the MediaRecorderErrorEvent interface with the error attribute set to error, must be created and dispatched at the given target.

dictionary MediaRecorderErrorEventInit : EventInit {
  required DOMException error;
};

[Exposed=Window, Constructor(DOMString type, MediaRecorderErrorEventInit eventInitDict)]
interface MediaRecorderErrorEvent : Event {
  [SameObject] readonly attribute DOMException error;
};

4.2.1. Constructors

MediaRecorderErrorEvent(DOMString type, MediaRecorderErrorEventInit eventInitDict)
Constructs a new MediaRecorderErrorEvent.
Parameter Type Nullable Optional Description
type DOMString
eventInitDict MediaRecorderErrorEventInit

4.2.2. Attributes

error, of type DOMException, readonly
The DOMException error that triggered the event.

4.2.3. MediaRecorderErrorEventInit

error, of type DOMException
The DOMException causing the error that triggered the event. An explanatory message about the error circumstances MAY be provided in its message attribute.
If an implementation places non-standard properties on DOMException, exposing e.g. stack traces or error line numbers, these are encouraged to point to whichever method call most closely identifies the run-time operation that caused the error, e.g. start().

4.3. Exception Summary

Each of the exceptions defined in this document is a DOMException with a specific type.

Name Description
InvalidStateError An operation was called on an object on which it is not allowed or at a time when it is not allowed, or if a request is made on a source object that has been deleted or removed.
NotSupportedError A MediaRecorder could not be created due to unsupported options (e.g. MIME type) specification. User agents should provide as much additional information as possible in the message attribute.
SecurityError The isolation properties of the MediaStream do not allow the MediaRecorder access to it.

5. Event summary

The following additional events fire on MediaRecorder objects:

Event name Interface Fired when...
start Event The UA has started recording data from the MediaStream.
stop Event The UA has stopped recording data from the MediaStream.
dataavailable BlobEvent The UA generates this even to return data to the application. The data attribute of this event contains a Blob of recorded data.
pause Event The UA has paused recording data from the MediaStream.
resume Event The UA has resumed recording data from the MediaStream.
error MediaRecorderErrorEvent An error has occurred, e.g. out of memory or a modification to the stream has occurred that makes it impossible to continue recording (e.g. a Track has been added to or removed from the said stream while recording is occurring).

6. Examples

Slightly modified versions of these examples can be found in e.g. this codepen collection.

6.1. Check for MediaRecorder and mime types

The following example can also be found in e.g. this codepen with minimal modifications.
if (window.MediaRecorder == undefined) {
  console.error('MediaRecorder not supported, boo');
} else {
  var contentTypes = ["video/webm",
                      "video/webm;codecs=vp8",
                      "video/x-matroska;codecs=avc1",
                      "audio/webm",
                      "video/mp4;codecs=avc1",
                      "video/invalid"];
  contentTypes.forEach(contentType => {
    console.log(contentType + ' is '
        + (MediaRecorder.isTypeSupported(contentType) ?
            'supported' : 'NOT supported '));
  });
}

6.2. Recording webcam video and audio

The following example can also be found in e.g. this codepen with minimal modifications.
<html>
<body>
<video autoplay/>
<script>
  var recordedChunks = [];

  function gotMedia(stream) {
    var video = document.querySelector('video');
    video.src = URL.createObjectURL(stream);
    var recorder = null;
    try {
      recorder = new MediaRecorder(stream, {mimeType : "video/webm"});
    } catch (e) {
      console.error('Exception while creating MediaRecorder: ' + e);
      return;
    }

    recorder.ondataavailable = (event) => {
      console.log(' Recorded chunk of size ' + event.data.size + "B");
      recordedChunks.push(event.data);
    };

    recorder.start(100);
  }

  navigator.mediaDevices.getUserMedia({video: true , audio: true})
      .then(gotMedia)
      .catch(e => { console.error('getUserMedia() failed: ' + e); });
</script>
</body>
</html>
recordedChunks can be saved to a file using e.g. the function download() in the MediaRecorder Web Fundamentals article.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Conformance Classes

A conformant user agent must implement all the requirements listed in this specification that are applicable to user agents.

A conformant server must implement all the requirements listed in this specification that are applicable to servers.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[FileAPI]
Arun Ranganathan; Jonas Sicking. File API. URL: https://w3c.github.io/FileAPI/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2046]
N. Freed; N. Borenstein. Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types. November 1996. Draft Standard. URL: https://tools.ietf.org/html/rfc2046
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. URL: https://heycam.github.io/webidl/
[WHATWG-DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/

Informative References

[RFC6381]
R. Gellens; D. Singer; P. Frojdh. The 'Codecs' and 'Profiles' Parameters for "Bucket" Media Types. August 2011. Proposed Standard. URL: https://tools.ietf.org/html/rfc6381

IDL Index

[Constructor(MediaStream stream, optional MediaRecorderOptions options)]
interface MediaRecorder : EventTarget {
  readonly attribute MediaStream stream;
  readonly attribute DOMString mimeType;
  readonly attribute RecordingState state;
  attribute EventHandler onstart;
  attribute EventHandler onstop;
  attribute EventHandler ondataavailable;
  attribute EventHandler onpause;
  attribute EventHandler onresume;
  attribute EventHandler onerror;
  readonly attribute unsigned long videoBitsPerSecond;
  readonly attribute unsigned long audioBitsPerSecond;

  void start(optional long timeslice);
  void stop();
  void pause();
  void resume();
  void requestData();

  static boolean isTypeSupported(DOMString type);
};

dictionary MediaRecorderOptions {
  DOMString mimeType;
  unsigned long audioBitsPerSecond;
  unsigned long videoBitsPerSecond;
  unsigned long bitsPerSecond;
};

enum RecordingState {
  "inactive",
  "recording",
  "paused"
};

[Constructor(DOMString type, BlobEventInit eventInitDict)]
interface BlobEvent : Event {
  [SameObject] readonly attribute Blob data;
  readonly attribute DOMHighResTimeStamp timecode;
};

dictionary BlobEventInit {
  required Blob data;
  DOMHighResTimeStamp timecode;
};

dictionary MediaRecorderErrorEventInit : EventInit {
  required DOMException error;
};

[Exposed=Window, Constructor(DOMString type, MediaRecorderErrorEventInit eventInitDict)]
interface MediaRecorderErrorEvent : Event {
  [SameObject] readonly attribute DOMException error;
};