-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
explainer for media controls #139
Conversation
|
||
attribute EventHandler onplay; | ||
attribute EventHandler onpause; | ||
attribute EventHandler onplaypause; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, do we need to support this? Android will automatically send play or pause if playpause is fired. iOS supports this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually the opposite. Both Android and iOS have "toggle play/pause". I think they are usually used for headset buttons.
Another issue related to play/pause is that how the user agent detects whether the page is playing or not. If the UA falsely detects a page is playing while the page thinks not, the page will always fire pause
instead of play
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now MediaSession has a list of events it wants to handle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just leave onplaypause event then?
Would we fire both onplay/onpause and onplaypause at the same time? This might get confusing to the page.
I'd argue that the browser has its own playing/paused state anyway (to show the right button on the notification or in the media controls) so if the browser detects it wrong, we're in trouble even without the MediaSession API.
We can always add onplaypause later if it's really needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean only have onplaypause
? Your first and last sentence seems contradicting. 😄
I agree with you, otherwise the page needs to specify the play/pause state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the example where UA can't detect the playback state correctly? My argument that the UA likely depends on detecting the playback state correctly already (it shows play/pause button on the media element controls and in the notification) so either we can assume it's correct or we need an API for the page to tell the UA to adjust the UI bits I mention above.
Keeping all three seems confusing. I imagine the page do something like:
var v = document.getElementById('video1');
navigator.mediaSession.onplay = function() { v.play(); };
navigator.mediaSession.onpause = function() { v.pause(); };
navigator.mediaSession.onplaypause = function() { if (v.paused) v.play(); else v.pause(); };
Now if the UA fires both onplay
and onplaypause
, the page may play()
and then pause()
the element depending on the order and timing of the events.
If the UA fires onplay
in some cases and onplaypause
in some others, I wonder what the cases are and if they can be listed in the spec so that the page knows when it needs to add one or the other event listener.
If the UA only fires onplay
and onpause
, it seems pretty straightforward for the page what to do.
If the UA fires only onplaypause
, the page might actually do the opposite of what the user expects: if the page maintains the state itself and it's not reflecting what the user sees in the browser UI. At the least, the page has to do some extra logic to check the state and it has no idea what the UA thinks about the playback state.
I think if the page wants to use MediaSession to control some paint-to-canvas animation (let's say with no sound), the UA can't reliably detect the playback state and we need some API for that (so we know when playback starts in the first place).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. Realized that onplaypause
is identical to onplay/onpause
+ a playback state, while the difference is the if
statement on the playback state is in the page or the UA.
Maybe we need to add attribute bool playbackState
in the future. If it is specified, the UA uses this info, otherwise the UA uses its best guess.
Is this better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the need for a playbackState is much more immediate. Both YouTube and Netflix have user-displayed playback state that does not match the
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I would either encourage adding a playbackstate
attribute immediately, or adding the onplaypause
command back.
attribute EventHandler onprevioustrack; | ||
attribute EventHandler onnexttrack; | ||
attribute EventHandler onseekforward; | ||
attribute EventHandler onseedbackward; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/onseed/onseek/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -96,20 +113,43 @@ interface MediaMetadata { | |||
|
|||
### Media controls | |||
|
|||
**Note** The spec will handle these use cases but not as part of the first | |||
iteration. | |||
**Note** The API for media controls are still under development and may not be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/ are still/ is still/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
readonly attribute supportsPreviousTrack; | ||
readonly attribute supportsNextTrack; | ||
readonly attribute supportsSeekForward; | ||
readonly attribute supportsSeekBackward; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these are readonly
, is it on purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These attributes are removed per our offline discussion
When pages registers event handlers to MediaSession, the page declares it can | ||
and want to accept these events. However, it is up to the user agent to decide | ||
which controls to show for in the UI and register callbacks to the | ||
platform. This may depend on UI concerns and platform capabilities. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/This may depend/This may vary depending/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
``` | ||
// Suppose |audio| is an audio element and |session| is a MediaSession object. | ||
if (!!session.supportsPlayPause) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Is supportsFoo
meant for the UA to expose that it supports some action? I was expecting the opposite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking if it would be useful if we expose the UA media controls capability to the page, but I haven't found a good use case yet. Maybe now we just remove all supports*
?
I think registering event handlers should be enough for the page to show its intention to handle the event?
ed6bf77
to
d937245
Compare
PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of comments are on the spec and API shape side of things (and nits). The gist of the change looks good :)
facilities, and forward the control event to the page by calling the | ||
corresponding event listener callbacks. | ||
|
||
Pages declare what events it wants to handle by setting the `eventList` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use the term action instead of events here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
attribute EventHandler onseekbackward; | ||
... | ||
|
||
attribute DOMString eventList = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be called supportedControls
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, what about Promise<> setSupportedControls(sequence<DOMString>)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also name this "setSupportedActions" if the naming sounds better. I'm not certain what to pick :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using supportedActions
since we are using the term action
consistently.
Maybe just throw an exception if the argument is illegal? I'm not sure what's the benefit of returning a Promise<>
, which makes the API asynchronous.
Also, I think we made metadata
as an attribute of MediaSession
for the race condition of a page setting metadata
in multiple places. Maybe supportedActions
also has the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree with mounirlamouri here. There's no need to have a separate call to setSupportedControls(). Adding event handlers implies that those events are supported.
Secondly, throwing an exception if one of the "controls" is unsupported is not future-proof. If the spec is changed to add (or remove) specific commands, page authors will be forced to try-and-retry various combinations of commands until they get one that doesn't throw an exception. The end result would be that pages would only ever support the intersection of all supported commands across both evergreen and legacy UAs.
The feature detection story of using the event handlers to show support for various commands is much better:
if (typeof(audio.onseekbackward) !== 'undefined')
audio.onseekbackward = mySeekHandler;
if (typeof(audio.onnewlyspecifiedcommand) !== 'undefined')
audio.onnewlyspecifiedcommand = myNewCommandHandler;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I did not think about throwing and forward compatibility. Good point.
For the events, this is something we did consider. To be explicit, something that might not be clear is that we want websites to express interest for a control/action that would allow the browser to show a UI for it. In addition of that, we want to offer a way for the websites to control this. For example, a website might want the UA to show seek backward/forward buttons but wouldn't need to do anything with the events. If we consider events to be the way for websites to express support/interest, it would require them to attach events doing nothing.
Maybe this isn't a strong use case and we shouldn't design the API around it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could go back to have a DOMString/sequence attribute and let it be totally a hint? Pages can set the value to whatever it want, and the UA will ignore unexpected values.
As you pointed, I'm also starting to wonder if this will be useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mounirlamouri: If you do want to support the use case of the page declaring support for a command but not wanting to override the default behavior for a command, the specification could say that the event handler must call preventDefault() to prevent the UA's default behavior for a given event (e.g., calling play() due to onplay(), etc.).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 That was my alternative design. Let's run with this for now and see if everyone is happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
event handler, the user agent may have fallback behaviors (such as handling | ||
"seekforward" internally). | ||
|
||
Please be aware that, it is up to the user agent to decide which controls to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove "Please be aware that". The audience for this document is not web developers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
attribute EventHandler onseekbackward; | ||
... | ||
|
||
attribute DOMString eventList = ""; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to have a list of supported actions/controls. It can be expressed via an enum. The spec will have to require the supported controls/actions passed to be from that list, otherwise throw an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
enum MediaSessionActions {
"play",
"pause",
...
};
The API for media controls should work as follows: | ||
|
||
* The page tells which media controls it would like to receive, and register | ||
corresponding callbacks to `MediaSession`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Which media controls it supports and would like the user agent to expose in its UI."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's already in the text bullet?
the event name in `eventList`, and register the corresponding event handler. In | ||
case of the page specifying event name in `eventList` while not registering an | ||
event handler, the user agent may have fallback behaviors (such as handling | ||
"seekforward" internally). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you should mention somewhere that an action should be marked as supported in order to receive an event because the UA might not expose the control otherwise. Also add that it's okay to mark an action as supported but not handle it, in which case the UA will do the default behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Rephrased the paragraphs around this location.
session.eventList = "playpause"; | ||
session.onplaypause = function() { | ||
if (audio.paused) | ||
play(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: audio.play();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (audio.paused) | ||
play(); | ||
else | ||
pause(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: audio.pause();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
4e7b227
to
91668ed
Compare
PTAL. Now using the |
91668ed
to
e729152
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm with comments
|
||
The user agent may have fallback behavior for some actions. There might be | ||
useful in several use cases where the page wants to use or override the default | ||
fallback behavior. Here are some possible solutions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not have the two bullet points and just say that preventDefault()
should be called to avoid the fallback behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
attribute `playbackState` to let the page tell the playback state correctly. In | ||
many cases, `play` and `pause` share the same media button. When the button is | ||
pressed, the user agent should fire `pause` action when the page is playing and | ||
fire `play` when the page is paused. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to put back playpause
and open an issue to discuss whether we should drop it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
e729152
to
8209617
Compare
No description provided.