HTMLMediaElement - detecting startup hysterisis

We have some concerns over the states, variables, and events that tell  
whether a media element is playing or not - specifically it is not  
possible to determine when media playback actually begins (time  
advances). This is problematic with a media resources served with a  
download protocol when playback is requested before media has been  
buffered, as well as with streaming protocols which do not keep any  
media data cached locally. For example, in a live stream scenario  
there is an indeterminate delay between when the media engine is told  
to play and when it receives media samples from the server. In both  
scenarios we feel that scripts will want to be able to reflect this  
transitional state in their UI so users are not confused when they  
press "play" and nothing happens immediately.

We would like to propose what we believe is a cleaner model. This  
proposal applies to all protocols and situations we can think of while  
remaining simple for the simple cases.

REVIEW

Today the spec describes the following relevant variables and events  
(although we have proposed removing defaultPlaybackRate [1])

playbackRate
defaultPlaybackRate
paused (boolean)
waiting (event)
ratechange (event)
play (event)
pause (event)

initially:
  defaultPlaybackRate := 1.0

on load():
  playbackRate := defaultPlaybackRate
  paused := true

on play():
  if (playbackRate != defaultPlaybackRate) fire(ratechange)
  playbackRate := defaultPlaybackRate
  if (paused) fire(play)
  paused := false

on pause():
  fire(pause)
  paused := true

on a stall:
  fire(waiting)

ratechange:
  fired when either playbackRate or defaultPlaybackRate changes

Changing playbackRate only affects what's happening if time is  
currently or potentially advancing, as any play() will over-write it.

Time may be advancing if I have not recently had a waiting event, or I  
have had a waiting event but looking at the readyState tells I should  
be no longer waiting (CAN_PLAY or greater) .

In this model any lag between asking for play and time advancing is  
poorly represented.  In fact, if there is a lag between play() and  
playback starting, I don't think I can tell -- I don't get a waiting  
event.  This can happen in download protocols as well as streaming.

The events do not always reflect a change of state, and not every  
change of state gives an alerting event.  (As noted, there is no way  
to tell reliably when I am waiting.)




PROPOSAL

playbackRate
playingState -- read-only variable, one of { NOT_PLAYING,  
PLAY_PENDING, PLAYING }
ratechange (event)
playpending (event)
playing (event)
play (event)
pause (event)

playingState values:
NOT_PLAYING :
  playback has not been requested
PLAY_PENDING :
   playback has been requested, but time is not currently advancing.  
(This may be because the media element is still loading, because it  
has stalled waiting for data, stalled waiting for interaction, or  
because it's a protocol with some lag between requesting data and  
starting playing.)
PLAYING :
  time is advancing at the playbackRate

ratechange is dispatched whenever playbackRate changes
playpending, playing, or pause is dispatched whenever playingState  
changes

initially:
   playingState := NOT_PLAYING
   playbackRate := 1.0

on load():
  paused := true

on play():
   if (paused) fire(play)
   if (playback can not begin immediately)
   {
       playingState := PLAY_PENDING
       fire (playpending)
   }

when playback begins:
   playingState := PLAYING
   fire (playing)

on pause():
   playingState := NOT_PLAYING
   fire(pause)

on a stall:
   if (playingState is PLAYING)
   {
       playingState := PLAY_PENDING
       fire (playpending)
   }


UA and scripts can only affect playingState by calling play() or  
pause().

UA and scripts can both write to playbackRate, but it will have effect  
whenever play happens, immediately if playingState == PLAYING.

Time is advancing if playingState == PLAYING.

Stalling, a lag between play() and starting to play, and so on, are  
all directly represented.

It is easy to handle multiple javascript controllers and a built-in  
one, and keep them in sync.


SUMMARY

remove defaultPlaybackRate (previously proposed)
remove waiting event

add playingState attribute
add playpending event
add playing event

eric

[1] http://lists.w3.org/Archives/Public/public-html/2008Nov/0416.html

Received on Wednesday, 26 November 2008 20:48:04 UTC