Rationalizing new/start/end/mute/unmute/enabled/disabled

I think that it's fair to say that the current state of the
MediaStream[Track] states is pretty dire.  At least from a usability
perspective.

Let's take a quick inventory:

MediaStreamTrack:
                attribute boolean               enabled;
    readonly    attribute MediaStreamTrackState readyState;
                attribute EventHandler          onstarted;
                attribute EventHandler          onmute;
                attribute EventHandler          onunmute;
                attribute EventHandler          onended;

MediaStream:
                attribute boolean      ended;
                attribute EventHandler onended;

On the track we have two state variables, one of them writeable, and
four events.  At a bare minimum, this could be a single onstatechange
event.

For the stream, I really don't know why I would want to set ended =
true on a stream.  The explanation doesn't cast any light on the
matter either.  Let's pretend that this is read-only for the moment.


Rendering

I believe that the gUM document needs to be very clear about the
rendering logic for MediaStream instances.  This is a little too
amorphous in the current document.  I propose a section or sub-section
entitled "Rendering MediaStreams" that has an explanation along the
lines of the following.

When a particular MediaStream instance is attached to a sink that
consumes only one source (not a mixing sink, like <audio> probably
will be), the output will be selected from the set of tracks in the
stream that:

 - are "live"; that is, in a readyState of "muted" or "unmuted" (not
"new" or "ended")
 - have enabled = true

...of course, media will only render (other than silence/black) if the
selected track's readyState is "unmuted".  I'm assuming here that
track selection does not examine the muted/unmuted state.

...but only if the stream itself is not ended.  Note that the stream
can be un-ended by adding an un-ended track.

A mixing sink (such as <audio>) renders multiple tracks
simultaneously, combining all candidate tracks.


Mute/unmute/enabled/disabled

Again, specific treatment of this relationship might make it easier to
understand.  A sub-section that is explicitly on this subject would
help.  Specifically:

A muted or disabled track renders either silence (audio), black frames
(video), or a zero-information-content equivalent.  Media flows only
when a track is both unmuted and enabled.  The muted/unmuted state of
a track is under user control, the enabled/disabled state is under
application control.

A track can be muted by a user.  Often this action is outside the
control of the application.  This could be as a result of the user
hitting a hardware switch, toggling a control in the operating system
or browser chrome, or as simple as throwing a hat over the camera.

Not all muting/unmuting actions can be detected by the browser
directly.  When a track is muted or unmuted in a way that is detected
by the browser, the browser fires a state change event [ref: actual
event description] to inform the application.

Applications are able to enable or disable tracks.  This is logically
equivalent to muting and unmuting, except that the application is in
control and the enabled/disabled state operates independently of the
muted/unmuted state.


Muted/unmuted/"readyState"

The lifecycle states of a track are now different to that of a stream.
 That might need fixing.  (Advertise "new" on stream while all tracks
are also "new").

But the key point I wanted to raise was that lifecycle and mute/unmute
operate independently.  They are orthogonal.  Third-normal form
dictates that we place these in different columns.

Yes, I will concede that you don't care about the muted/unmuted state
of a track in any state other than "live", that's not the point.  It's
hard to form thoughts about something, or explain it effectively if
you conflate concepts.

Proposal:

MediaStreamTrack:
    attribute boolean enabled [= true];
  readonly attribute boolean muted;
  readonly attribute LiveCycleStateEnum state = ["new" / "live" / "ended"];
    attribute EventHandler onmute; // and unmute, attach a boolean to
the event details
    attribute EventHandler onstatechange; // one handler per state
variable, not 4

MediaStream:
  readonly attribute LiveCycleStateEnum state = ["new" / "live" / "ended"];
   // where "new" or "ended" only if all tracks are in that state.
    attribute EventHandler onstatechange; // one handler per state
variable, not 4

I can live with having mute+lifecycle states conflated.  I can see how
that would be convenient in some cases.  It's only a reporting
interface after all.  No harm in doing the right thing from the outset
though.

Received on Monday, 25 March 2013 21:55:36 UTC