[The MediaElement IDL is repeated for reference at the bottom of this page]

A MediaStream may be assigned to media elements as defined in HTML5 by calling createObjectURL to obtain a URL for the MediaStream and then setting the media elements 'src' attribute to that url. [OPEN ISSUE: do we also need to support direct assignment and access of the underlying stream?] A MediaStream is not preloadable or seekable and represents a simple, potentially infinite, linear media timeline. The timeline starts at 0 and increments linearly in real time as long as the MediaStream is playing. The timeline does not increment when the MediaStream is paused.

The nature of the MediaStream places certain restrictions on the attribute values of the associated media element and on the operations that can be performed on it, as shown below:

Attribute Name Attribute Type Valid Values Additional considerations
src DOMString a local URI referencing a MediaStream N.B. Revocation of the URL does not count as a change to this field. [NOTE: I'm assuming that revoking the URL does not destroy the underlying MediaStream resourse.]
currentSrc DOMString a local URI referencing a MediaStream -
preload DOMString 'None' A MediaStream cannot be preloaded.
buffered TimeRanges buffered.length must return 1.
buffered.start(0) must return 0.
buffered.end(0) must return 0.
A MediaStream cannot be preloaded. Therefore the amount buffered is always an empty TimeRange.
void load() procedure Not applicable. This procedure causes the UA to run the media element load algorithm. When the UA reaches the resource fetch phase of this algorithm and determines that the media resource in question is a MediaStream, it must immediately abort the resource selection algorithm, acting as if the entire resource has been loaded and kept available.
currentTime double Any positive integer. The initial value is 0 and the values increments linearly in real time whenever the stream is playing. The value is the current stream position, in seconds. The UA must ignore attempts to set this attribute.
duration double Infinity A MediaStream does not have a pre-defined duration.

If the underlying MediaStream is destroyed, the UA must be set this property to the value of the last known currentTime.

seeking boolean false A MediaStream is not seekable. Therefore this attribute must always have the value false.
defaultPlaybackRate double 1.0 A MediaStream is not seekable. Therefore this attribute must always have the value 1.0 and any attempt to alter it must fail.
playbackRate double 1.0 A MediaStream is not seekable. Therefore this attribute must always have the value 1.0 and any attempt to alter it must fail.
played TimeRanges played.length must return 1.
played.start(0) must return 0.
played.end(0) must return the last known currentTime.
A MediaStream's timeline always consists of a single range, starting at 0 and extending up to the currentTime.
seekable TimeRanges seekable.length must return 0.
seekable.start() must return 0.
seekable.end() must return 0.
A MediaStream is not seekable. [ISSUE: the original Opera proposal said that seekable.start() and seekable.end() should throw errors. However, the definition of an HTML5 Media Controller requires it to take the intersection of the seekable ranges of the streams it controls (in order to synchronize them). Should a function that a MediaController may be required to call return an error? ]
startOffsetTime Date Not-a-Number (NaN) A MediaStream does not specify a timeline offset.
loop boolean false A MediaStream has no defined end and therefore cannot be looped.

[OTHER QUESTIONS: Do we need to be explicit about 'empty' edge cases? For example, it doesn't make much sense to assign a MediaController to a MediaStream, but as far as I can tell nothing would break. Do we need to say anything about this? Similarly, a MediaStream won't have TextTracks, but since they're optional we may not need to say anything about them either.]

interface HTMLMediaElement : HTMLElement {

  // error state
  readonly attribute MediaError? error;

  // network state
           attribute DOMString src;
  readonly attribute DOMString currentSrc;
           attribute DOMString crossOrigin;
  const unsigned short NETWORK_EMPTY = 0;
  const unsigned short NETWORK_IDLE = 1;
  const unsigned short NETWORK_LOADING = 2;
  const unsigned short NETWORK_NO_SOURCE = 3;
  readonly attribute unsigned short networkState;
           attribute DOMString preload;
  readonly attribute TimeRanges buffered;
  void load();
  DOMString canPlayType(DOMString type);

  // ready state
  const unsigned short HAVE_NOTHING = 0;
  const unsigned short HAVE_METADATA = 1;
  const unsigned short HAVE_CURRENT_DATA = 2;
  const unsigned short HAVE_FUTURE_DATA = 3;
  const unsigned short HAVE_ENOUGH_DATA = 4;
  readonly attribute unsigned short readyState;
  readonly attribute boolean seeking;

  // playback state
           attribute double currentTime;
  readonly attribute double initialTime;
  readonly attribute double duration;
  readonly attribute Date startOffsetTime;
  readonly attribute boolean paused;
           attribute double defaultPlaybackRate;
           attribute double playbackRate;
  readonly attribute TimeRanges played;
  readonly attribute TimeRanges seekable;
  readonly attribute boolean ended;
           attribute boolean autoplay;
           attribute boolean loop;
  void play();
  void pause();

  // media controller
           attribute DOMString mediaGroup;
           attribute MediaController? controller;

  // controls
           attribute boolean controls;
           attribute double volume;
           attribute boolean muted;
           attribute boolean defaultMuted;

  // tracks
  readonly attribute AudioTrackList audioTracks;
  readonly attribute VideoTrackList videoTracks;
  readonly attribute TextTrackList textTracks;
  TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language);
};