Skip to content

Commit

Permalink
Make HTMLMediaElement.prototype.play() return a promise
Browse files Browse the repository at this point in the history
This is allowing a simpler flow to know whether playback started or
whether it failed. It also allows the UA to reject the promise if
playback is not allowed in the current context, solving issues websites
have to detect whether autoplay restrictions blocked the playback.

Closes #505.
  • Loading branch information
mounirlamouri committed Feb 1, 2016
1 parent 0b62bea commit be8edde
Showing 1 changed file with 124 additions and 33 deletions.
157 changes: 124 additions & 33 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -2897,21 +2897,23 @@ a.setAttribute('href', 'http://example.com/'); // change the content attribute d
WebIDL specification. The following exception names are defined by WebIDL and used by this
specification:</p>

<ol class="brief">
<li value="1"><dfn data-noexport=""><code>IndexSizeError</code></dfn></li>
<li value="3"><dfn data-noexport=""><code>HierarchyRequestError</code></dfn></li>
<li value="5"><dfn data-noexport=""><code>InvalidCharacterError</code></dfn></li>
<li value="8"><dfn data-noexport=""><code>NotFoundError</code></dfn></li>
<li value="9"><dfn data-noexport=""><code>NotSupportedError</code></dfn></li>
<li value="11"><dfn data-noexport=""><code>InvalidStateError</code></dfn></li>
<li value="12"><dfn data-noexport=""><code>SyntaxError</code></dfn></li>
<li value="15"><dfn data-noexport=""><code>InvalidAccessError</code></dfn></li>
<li value="18"><dfn data-noexport=""><code>SecurityError</code></dfn></li>
<li value="19"><dfn data-noexport=""><code>NetworkError</code></dfn></li>
<li value="22"><dfn data-noexport=""><code>QuotaExceededError</code></dfn></li>
<li value="23"><dfn data-noexport=""><code>TimeoutError</code></dfn></li>
<li value="25"><dfn data-noexport=""><code>DataCloneError</code></dfn></li>
</ol>
<ul class="brief">
<li><dfn data-noexport=""><code>IndexSizeError</code></dfn></li>
<li><dfn data-noexport=""><code>HierarchyRequestError</code></dfn></li>
<li><dfn data-noexport=""><code>InvalidCharacterError</code></dfn></li>
<li><dfn data-noexport=""><code>NotFoundError</code></dfn></li>
<li><dfn data-noexport=""><code>NotSupportedError</code></dfn></li>
<li><dfn data-noexport=""><code>InvalidStateError</code></dfn></li>
<li><dfn data-noexport=""><code>SyntaxError</code></dfn></li>
<li><dfn data-noexport=""><code>InvalidAccessError</code></dfn></li>
<li><dfn data-noexport=""><code>SecurityError</code></dfn></li>
<li><dfn data-noexport=""><code>NetworkError</code></dfn></li>
<li><dfn data-noexport=""><code>AbortError</code></dfn></li>
<li><dfn data-noexport=""><code>QuotaExceededError</code></dfn></li>
<li><dfn data-noexport=""><code>TimeoutError</code></dfn></li>
<li><dfn data-noexport=""><code>DataCloneError</code></dfn></li>
<li><dfn data-noexport=""><code>NotAllowedError</code></dfn></li>
</ul>

<p>When this specification requires a user agent to <dfn data-noexport="">create a
<code>Date</code> object</dfn> representing a particular time (which could be the
Expand Down Expand Up @@ -29258,7 +29260,7 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
readonly attribute boolean <span data-x="dom-media-ended">ended</span>;
attribute boolean <span data-x="dom-media-autoplay">autoplay</span>;
attribute boolean <span data-x="dom-media-loop">loop</span>;
void <span data-x="dom-media-play">play</span>();
Promise&lt;void&gt; <span data-x="dom-media-play">play</span>();
void <span data-x="dom-media-pause">pause</span>();

// media controller
Expand Down Expand Up @@ -29726,8 +29728,10 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
data-x="task queue">task queues</span>, then remove those tasks.</p>
-->

<p class="note">Basically, pending events and callbacks for the media element are discarded when
the media element starts loading a new resource.</p>
<p><span>Reject pending play promises</span> with <code>AbortError</code>.</p>

<p class="note">Basically, pending events and callbacks are discarded and pending promises are
rejected when the media element starts loading a new resource.</p>

</li>

Expand Down Expand Up @@ -30117,6 +30121,8 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
<li><p><span>Fire a simple event</span> named <code data-x="event-media-error">error</code> at
the <span>media element</span>.</p></li>

<li><p><span>Reject pending play promises</span> with <code>NotSupportedError</code>.</p></li>

<li><p>Set the element's <span>delaying-the-load-event flag</span> to false. This stops <span
data-x="delay the load event">delaying the load event</span>.</p></li>

Expand Down Expand Up @@ -31335,8 +31341,7 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
<code data-x="event-media-canplay">canplay</code> at the element.</p>

<p>If the element's <code data-x="dom-media-paused">paused</code> attribute is false, the user
agent must <span>queue a task</span> to <span>fire a simple event</span> named <code
data-x="event-media-playing">playing</code> at the element.</p>
agent must <span>queue a task</span> to <span>notify about playing</span> for the element.</p>

</dd>

Expand All @@ -31351,8 +31356,7 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
<span>queue a task</span> to <span>fire a simple event</span> named <code
data-x="event-media-canplay">canplay</code> at the element, and, if the element's <code
data-x="dom-media-paused">paused</code> attribute is false, <span>queue a task</span> to
<span>fire a simple event</span> named <code data-x="event-media-playing">playing</code>
at the element.</p>
<span>notify about playing</span> for the element.</p>

<p>If the <span>autoplaying flag</span> is true, and the <code
data-x="dom-media-paused">paused</code> attribute is true, and the <span>media element</span>
Expand All @@ -31371,8 +31375,7 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
<li><span>Queue a task</span> to <span>fire a simple event</span> named <code
data-x="event-media-play">play</code> at the element.</li>

<li><span>Queue a task</span> to <span>fire a simple event</span> named <code
data-x="event-media-playing">playing</code> at the element.</li>
<li><span>Queue a task</span> to <span>notify about playing</span> for the element.</li>

<li>Set the <span>autoplaying flag</span> to false.</li>

Expand Down Expand Up @@ -31729,11 +31732,79 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {

<hr>

<p>Each <span>media element</span> has a <dfn>list of pending play promises</dfn>, which must
initially be empty.</p>

<p>To <dfn>resolve pending play promises</dfn> for a <span>media element</span>, the user agent
must run the following steps:</p>

<ol>

<li><p>For each promise in the <span>media element</span>'s <span>list of pending play
promises</span>, resolve it with undefined.</p></li>

<li><p>Clear the <span>media element</span>'s <span>list of pending play
promises</span>.</p></li>

</ol>

<p>To <dfn>reject pending play promises</dfn> for a <span>media element</span> with an exception
name <var>error</var>, the user agent must run the following steps:</p>

<ol>

<li><p>For each promise in the <span>media element</span>'s <span>list of pending play
promises</span>, reject it with an <var>error</var> exception.</p></li>

<li><p>Clear the <span>media element</span>'s <span>list of pending play
promises</span>.</p></li>

</ol>

<p>To <dfn>notify about playing</dfn> for a <span>media element</span>, the user agent must run
the following steps:</p>

<ol>

<li><p><span>Fire a simple event</span> named <code data-x="event-media-playing">playing</code>
at the element.</p></li>

<li><p><span>Resolve pending play promises</span>.</p></li>

</ol>

<p>When the <dfn><code data-x="dom-media-play">play()</code></dfn> method on a <span>media
element</span> is invoked, the user agent must run the following steps.</p>

<ol>

<li>

<p>Optionally, if the user agent or the system does not allow media playback in the current
context, return a promise rejected with a <code>NotAllowedError</code> exception and abort these
steps.</p>

<p class="note">For example, a user agent could require user interaction in order to start
playback. This specification does not require any particular behavior.</p>

</li>

<li>

<p>If the <span>media element</span>'s <code data-x="dom-media-error">error</code> attribute is
not null and its <code data-x="dom-MediaError-code">code</code> attribute has the value <code
data-x="dom-MediaError-MEDIA_ERR_SRC_NOT_SUPPORTED">MEDIA_ERR_SRC_NOT_SUPPORTED</code>, return a
promise rejected with a <code>NotSupportedError</code> exception and abort these steps.</p>

<p class="note">This means that the <span>dedicated media source failure steps</span> have run.
Playback is not possible until the <span>media element load algorithm</span> clears the <code
data-x="dom-media-error">error</code> attribute.</p>

</li>

<li><p>Let <var>promise</var> be a new promise and append <var>promise</var> to the <span>list of
pending play promises</span>.</p></li>

<li><p>If the <span>media element</span>'s <code
data-x="dom-media-networkState">networkState</code> attribute has the value <code
data-x="dom-media-NETWORK_EMPTY">NETWORK_EMPTY</code>, invoke the <span>media element</span>'s
Expand Down Expand Up @@ -31784,21 +31855,36 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {
data-x="dom-media-readyState">readyState</code> attribute has the value <code
data-x="dom-media-HAVE_FUTURE_DATA">HAVE_FUTURE_DATA</code> or <code
data-x="dom-media-HAVE_ENOUGH_DATA">HAVE_ENOUGH_DATA</code>: <span>queue a task</span> to
<span>fire a simple event</span> named <code data-x="event-media-playing">playing</code> at the
element.</p>
<span>notify about playing</span> for the element.</p>

</li>

</ol>

</li>

<li>

<p>Otherwise, if the <span>media element</span>'s <code
data-x="dom-media-readyState">readyState</code> attribute has the value <code
data-x="dom-media-HAVE_FUTURE_DATA">HAVE_FUTURE_DATA</code> or <code
data-x="dom-media-HAVE_ENOUGH_DATA">HAVE_ENOUGH_DATA</code>, <span>queue a task</span> to
<span>resolve pending play promises</span>.</p>

<p class="note">The media element is already playing. However, it's possible that
<var>promise</var> will be <span data-x="reject pending play promises">rejected</span> before
the queued task is run.</p>

</li>

<li><p>Set the <span>media element</span>'s <span>autoplaying flag</span> to false.</p></li>

<li><p>If the <span>media element</span> has a <span>current media controller</span>, then
<span>report the controller state</span> for the <span>media element</span>'s <span>current media
controller</span>.</p></li>

<li><p>Return <var>promise</var>.</p></li>

</ol>

<hr>
Expand Down Expand Up @@ -31831,14 +31917,19 @@ interface <dfn>HTMLMediaElement</dfn> : <span>HTMLElement</span> {

<li><p>Change the value of <code data-x="dom-media-paused">paused</code> to true.</p></li>

<li><p><span>Queue a task</span> to <span>fire a simple
event</span> named <code
data-x="event-media-timeupdate">timeupdate</code> at the
element.</p></li>
<li><p><span>Queue a task</span> to:</p></li>

<ol>

<li><p><span>Fire a simple event</span> named <code
data-x="event-media-timeupdate">timeupdate</code> at the element.</p></li>

<li><p><span>Queue a task</span> to <span>fire a simple
event</span> named <code data-x="event-media-pause">pause</code>
at the element.</p></li>
<li><p><span>Fire a simple event</span> named <code data-x="event-media-pause">pause</code> at
the element.</p></li>

<li><p><span>Reject pending play promises</span> with <code>AbortError</code>.</p></li>

</ol>

<li><p>Set the <span>official playback position</span> to the <span>current playback
position</span>.</p></li>
Expand Down

0 comments on commit be8edde

Please sign in to comment.