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

I think this is good.  A couple of questions:
1.  Why does MediaStream need a state at all?  Is it just a convenient shorthand for the combination of its Tracks' state? (so the app can check the MediaStream state to see if there are any live Tracks, rather than having to iterate over the individual Tracks)  Is the MediaStream state in any way logically separate from its Tracks' states?  I don't object to having state on the MediaStream, but would like to be clear about what it's for.

2.  Is it really simpler to have a single onstatechange handler?  The code inside every one of them will be a big case statement:  if started do this, if ended do this, etc.  I would think that you might get cleaner code by breaking each out into its own handler.  If we wrote a standard state machine diagram (UML or the  like) for a Track, it will show the individual started/ended events, and not a generic statechange event.  I realize that this may be just a matter of taste, but I think that the easier we make it for the programmer to visualize the UML statechart, the better the code will be.

- Jim 

-----Original Message-----
From: Martin Thomson [mailto:martin.thomson@gmail.com] 
Sent: Monday, March 25, 2013 5:55 PM
To: public-media-capture@w3.org
Subject: 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 22:35:00 UTC