From 723778c918cef0d71f8c462853570479e3a2f26b Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Mon, 25 Mar 2019 16:18:48 -0700 Subject: [PATCH 1/7] Add proposed explainer --- explainer.md | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 explainer.md diff --git a/explainer.md b/explainer.md new file mode 100644 index 0000000..4203b17 --- /dev/null +++ b/explainer.md @@ -0,0 +1,170 @@ +# Autoplay Detection API + +## Problem +If a website plays a video it cannot detect whether it will be allowed to autoplay or whether that autoplay will be blocked +until it calls play on the media element. + +## Goal +A site should be able to determine whether a video will autoplay or not. Knowing this in advance is important for a site +as they may want to adjust their user experience or select alternate content to use instead. + +## Proposed API Design +The document has an autoplay policy which can change. There will be an API on the document to get the autoplay policy and +another on the media element which will return a boolean as to whether the media will be able to autoplay. + +There are three types of autoplay policy: + + * `allowed` - autoplay is allowed + * `allowed-muted` - muted autoplay is allowed + * `disallowed` - document level autoplay is not allowed. The site should check on the element whether element level + autoplay is allowed + +The API is defined as the following: + +```javascript +enum AutoplayPolicy { + “allowed”, + “allowed-muted”, + “disallowed”, + “unknown” +}; + +partial interface Document { + Promise getAutoplayPolicy(); +}; + +partial interface HTMLMediaElement { + Promise canAutoplay(); +}; +``` + +The API should be async because determining whether a site can autoplay can require cross-process communications to +gather data such as website settings or user preferences. In this design the browser does not need to calculate the +autoplay policy until getAutoplayPolicy is called. Being async also does not limit browser implementations of what +determines autoplay policy. + +## Sample Code + +### A site would like to change the source based on whether it will autoplay + +In this situation a site would like to change the source based on whether it will autoplay. In this example the site +will play `video.webm` if it can autoplay unmuted. If it cannot then it will use `video-alt.webm` instead. + +```javascript +let policy = await document.getAutoplayPolicy(); + +if (policy == “allowed”) { + loadUnmutedVideo(); +} else { + loadMutedVideo(); +} +``` + +### A site would like to change its experience based on whether it will autoplay + +In this situation a site would like to change its experience based on whether it will autoplay. In this example if it +cannot autoplay unmuted then it will mute the video element. + +```javascript +let policy = await document.getAutoplayPolicy(); + +video.src = “video.webm”; +video.muted = !await video.canAutoplay(); +video.play(); +``` + +## Open questions + +### Sync vs Async + +There is a strong disagreement about whether this API should be synchronous instead (the sync design is supported by +both Apple and Mozilla). However, it would require all browsers to always be able to answer whether a website can +autoplay at load time; regardless of their autoplay policies. + +The synchronous API would be designed like this: + +```javascript +partial interface Document { + readonly attribute AutoplayPolicy autoplayPolicy; + attribute EventHandler onautoplaypolicychange; +}; + +partial interface HTMLMediaElement { + readonly boolean canAutoplay; +}; +``` + +The first example from above using this design would be as follows: + +```javascript +if (document.autoplayPolicy == “allowed”) { + loadUnmutedVideo(); +} else { + loadMutedVideo(); +} +``` + +The second example from above using this design would be as follows: + +```javascript +video.src = “video.webm”; +video.muted = !video.canAutoplay; +video.play(); +``` + +### Promise based API that returns an object + +An alternate design is for a promise based API that returns an object. AutoplayPolicyType here is an enum of the +different policies defined above. In this design, a site would call getAutoplayPolicy the first time to get the +object and then the object will be updated. This has the advantage that the browser does not need to determine the +autoplay policy until getAutoplayPolicy is called. This design has the advantage that is allows the website to warm +up the code path and avoid delays due to asynchronousity if they want to. + +```javascript +interface AutoplayPolicy : EventTarget { + readonly attribute AutoplayPolicyType type; + attribute EventHandler onchange; +}; + +partial interface Document { + readonly attribute Promise getAutoplayPolicy; +}; + +partial interface HTMLMediaElement { + Promise canAutoplay(); +}; +``` + +The first example from above using this design would be as follows: + +```javascript +let policy = await document.getAutoplayPolicy(); + +if (policy.type == “allowed”) { + loadUnmutedVideo(); +} else { + loadMutedVideo(); +} +``` + +The second example from above using this design would be as follows: + +```javascript +let policy = await document.getAutoplayPolicy(); + +video.src = “video.webm”; +video.muted = !await video.canAutoplay(); +video.play(); +``` + +### Event Listener Issue + +We received some feedback that if you have a bunch of videos on the page that are all listening to the autoplay +policy which becomes allowed and they all start playing together. + +## Considered Alternatives + +### Autoplay Permission + +We considered having autoplay as a permission. However, autoplay is not something the site should be able to request; +instead autoplay should be something the browser applies to a site. From e7788b46a024b4eb17c227502b43bce66a38d74f Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Mon, 25 Mar 2019 16:21:13 -0700 Subject: [PATCH 2/7] Update explainer.md --- explainer.md | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/explainer.md b/explainer.md index 4203b17..35dad86 100644 --- a/explainer.md +++ b/explainer.md @@ -1,23 +1,19 @@ # Autoplay Detection API ## Problem -If a website plays a video it cannot detect whether it will be allowed to autoplay or whether that autoplay will be blocked -until it calls play on the media element. +If a website plays a video it cannot detect whether it will be allowed to autoplay or whether that autoplay will be blocked until it calls play on the media element. ## Goal -A site should be able to determine whether a video will autoplay or not. Knowing this in advance is important for a site -as they may want to adjust their user experience or select alternate content to use instead. +A site should be able to determine whether a video will autoplay or not. Knowing this in advance is important for a site as they may want to adjust their user experience or select alternate content to use instead. ## Proposed API Design -The document has an autoplay policy which can change. There will be an API on the document to get the autoplay policy and -another on the media element which will return a boolean as to whether the media will be able to autoplay. +The document has an autoplay policy which can change. There will be an API on the document to get the autoplay policy and another on the media element which will return a boolean as to whether the media will be able to autoplay. There are three types of autoplay policy: * `allowed` - autoplay is allowed * `allowed-muted` - muted autoplay is allowed - * `disallowed` - document level autoplay is not allowed. The site should check on the element whether element level - autoplay is allowed + * `disallowed` - document level autoplay is not allowed. The site should check on the element whether element level autoplay is allowed The API is defined as the following: @@ -38,17 +34,13 @@ partial interface HTMLMediaElement { }; ``` -The API should be async because determining whether a site can autoplay can require cross-process communications to -gather data such as website settings or user preferences. In this design the browser does not need to calculate the -autoplay policy until getAutoplayPolicy is called. Being async also does not limit browser implementations of what -determines autoplay policy. +The API should be async because determining whether a site can autoplay can require cross-process communications to gather data such as website settings or user preferences. In this design the browser does not need to calculate the autoplay policy until getAutoplayPolicy is called. Being async also does not limit browser implementations of what determines autoplay policy. ## Sample Code ### A site would like to change the source based on whether it will autoplay -In this situation a site would like to change the source based on whether it will autoplay. In this example the site -will play `video.webm` if it can autoplay unmuted. If it cannot then it will use `video-alt.webm` instead. +In this situation a site would like to change the source based on whether it will autoplay. In this example the site will play `video.webm` if it can autoplay unmuted. If it cannot then it will use `video-alt.webm` instead. ```javascript let policy = await document.getAutoplayPolicy(); @@ -62,8 +54,7 @@ if (policy == “allowed”) { ### A site would like to change its experience based on whether it will autoplay -In this situation a site would like to change its experience based on whether it will autoplay. In this example if it -cannot autoplay unmuted then it will mute the video element. +In this situation a site would like to change its experience based on whether it will autoplay. In this example if it cannot autoplay unmuted then it will mute the video element. ```javascript let policy = await document.getAutoplayPolicy(); @@ -77,9 +68,7 @@ video.play(); ### Sync vs Async -There is a strong disagreement about whether this API should be synchronous instead (the sync design is supported by -both Apple and Mozilla). However, it would require all browsers to always be able to answer whether a website can -autoplay at load time; regardless of their autoplay policies. +There is a strong disagreement about whether this API should be synchronous instead (the sync design is supported by both Apple and Mozilla). However, it would require all browsers to always be able to answer whether a website can autoplay at load time; regardless of their autoplay policies. The synchronous API would be designed like this: @@ -114,11 +103,7 @@ video.play(); ### Promise based API that returns an object -An alternate design is for a promise based API that returns an object. AutoplayPolicyType here is an enum of the -different policies defined above. In this design, a site would call getAutoplayPolicy the first time to get the -object and then the object will be updated. This has the advantage that the browser does not need to determine the -autoplay policy until getAutoplayPolicy is called. This design has the advantage that is allows the website to warm -up the code path and avoid delays due to asynchronousity if they want to. +An alternate design is for a promise based API that returns an object. AutoplayPolicyType here is an enum of the different policies defined above. In this design, a site would call getAutoplayPolicy the first time to get the object and then the object will be updated. This has the advantage that the browser does not need to determine the autoplay policy until getAutoplayPolicy is called. This design has the advantage that is allows the website to warm up the code path and avoid delays due to asynchronousity if they want to. ```javascript interface AutoplayPolicy : EventTarget { @@ -159,12 +144,10 @@ video.play(); ### Event Listener Issue -We received some feedback that if you have a bunch of videos on the page that are all listening to the autoplay -policy which becomes allowed and they all start playing together. +We received some feedback that if you have a bunch of videos on the page that are all listening to the autoplay policy which becomes allowed and they all start playing together. ## Considered Alternatives ### Autoplay Permission -We considered having autoplay as a permission. However, autoplay is not something the site should be able to request; -instead autoplay should be something the browser applies to a site. +We considered having autoplay as a permission. However, autoplay is not something the site should be able to request; instead autoplay should be something the browser applies to a site. From ca9e15c5e72a587f5b869ea5fe73e73d68b47377 Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Tue, 26 Mar 2019 09:28:02 -0700 Subject: [PATCH 3/7] Update explainer.md --- explainer.md | 52 +++++++--------------------------------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/explainer.md b/explainer.md index 35dad86..653dd8f 100644 --- a/explainer.md +++ b/explainer.md @@ -101,53 +101,15 @@ video.muted = !video.canAutoplay; video.play(); ``` -### Promise based API that returns an object - -An alternate design is for a promise based API that returns an object. AutoplayPolicyType here is an enum of the different policies defined above. In this design, a site would call getAutoplayPolicy the first time to get the object and then the object will be updated. This has the advantage that the browser does not need to determine the autoplay policy until getAutoplayPolicy is called. This design has the advantage that is allows the website to warm up the code path and avoid delays due to asynchronousity if they want to. - -```javascript -interface AutoplayPolicy : EventTarget { - readonly attribute AutoplayPolicyType type; - attribute EventHandler onchange; -}; - -partial interface Document { - readonly attribute Promise getAutoplayPolicy; -}; - -partial interface HTMLMediaElement { - Promise canAutoplay(); -}; -``` - -The first example from above using this design would be as follows: - -```javascript -let policy = await document.getAutoplayPolicy(); - -if (policy.type == “allowed”) { - loadUnmutedVideo(); -} else { - loadMutedVideo(); -} -``` - -The second example from above using this design would be as follows: - -```javascript -let policy = await document.getAutoplayPolicy(); - -video.src = “video.webm”; -video.muted = !await video.canAutoplay(); -video.play(); -``` - ### Event Listener Issue -We received some feedback that if you have a bunch of videos on the page that are all listening to the autoplay policy which becomes allowed and they all start playing together. - -## Considered Alternatives +We considered having an event listener to allow sites to listen to changes in autoplay policy. However, this may cause issues where there are multiple event listeners on a page that all start playing when the autoplay policy changes. ### Autoplay Permission -We considered having autoplay as a permission. However, autoplay is not something the site should be able to request; instead autoplay should be something the browser applies to a site. +We considered having autoplay as a permission. However, there are a few differences between the autoplay and permissions: + + * Autoplay is something that is applied to the site from the browser; rather than something that should be requested + * Autoplay has multiple states (e.g. allowed, allowed-muted); rather than a yes or no + * Autoplay is not implemented by the user agents as a permission + * Permissions are async From 414ad3c3ac0c4b5f08b4be22d8ee9b8b899504bf Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Tue, 26 Mar 2019 16:18:02 -0700 Subject: [PATCH 4/7] Fix quotes --- explainer.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/explainer.md b/explainer.md index 653dd8f..b9e828a 100644 --- a/explainer.md +++ b/explainer.md @@ -19,10 +19,10 @@ The API is defined as the following: ```javascript enum AutoplayPolicy { - “allowed”, - “allowed-muted”, - “disallowed”, - “unknown” + "allowed", + "allowed-muted", + "disallowed", + "unknown” }; partial interface Document { @@ -45,7 +45,7 @@ In this situation a site would like to change the source based on whether it wil ```javascript let policy = await document.getAutoplayPolicy(); -if (policy == “allowed”) { +if (policy == "allowed") { loadUnmutedVideo(); } else { loadMutedVideo(); @@ -59,7 +59,7 @@ In this situation a site would like to change its experience based on whether it ```javascript let policy = await document.getAutoplayPolicy(); -video.src = “video.webm”; +video.src = "video.webm"; video.muted = !await video.canAutoplay(); video.play(); ``` @@ -86,7 +86,7 @@ partial interface HTMLMediaElement { The first example from above using this design would be as follows: ```javascript -if (document.autoplayPolicy == “allowed”) { +if (document.autoplayPolicy == "allowed") { loadUnmutedVideo(); } else { loadMutedVideo(); @@ -96,7 +96,7 @@ if (document.autoplayPolicy == “allowed”) { The second example from above using this design would be as follows: ```javascript -video.src = “video.webm”; +video.src = "video.webm"; video.muted = !video.canAutoplay; video.play(); ``` From 696853108eb4e52133859d89845bc0b370e2d9d9 Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Tue, 26 Mar 2019 16:20:16 -0700 Subject: [PATCH 5/7] Update AutoplayPolicy enum --- explainer.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/explainer.md b/explainer.md index b9e828a..59bd054 100644 --- a/explainer.md +++ b/explainer.md @@ -21,8 +21,7 @@ The API is defined as the following: enum AutoplayPolicy { "allowed", "allowed-muted", - "disallowed", - "unknown” + "disallowed" }; partial interface Document { From b8f4d344186252ec819fce29c263f3db7f9cce35 Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Thu, 28 Mar 2019 09:10:36 -0700 Subject: [PATCH 6/7] Highlight issue #7 more --- explainer.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/explainer.md b/explainer.md index 59bd054..29ff316 100644 --- a/explainer.md +++ b/explainer.md @@ -35,6 +35,8 @@ partial interface HTMLMediaElement { The API should be async because determining whether a site can autoplay can require cross-process communications to gather data such as website settings or user preferences. In this design the browser does not need to calculate the autoplay policy until getAutoplayPolicy is called. Being async also does not limit browser implementations of what determines autoplay policy. +**There is strong disagreement over whether this API should be async or sync. For more details about the pros/cons please see this issue: https://github.com/WICG/autoplay/issues/7** + ## Sample Code ### A site would like to change the source based on whether it will autoplay From b91f8ef3eee11fb4c19748a30a73bed766797aab Mon Sep 17 00:00:00 2001 From: Chris Needham Date: Wed, 13 Apr 2022 17:05:56 +0100 Subject: [PATCH 7/7] Update explainer to latest API shape --- explainer.md | 76 +++++++++++++++++----------------------------------- 1 file changed, 24 insertions(+), 52 deletions(-) diff --git a/explainer.md b/explainer.md index 29ff316..3a9fb44 100644 --- a/explainer.md +++ b/explainer.md @@ -1,12 +1,15 @@ # Autoplay Detection API ## Problem + If a website plays a video it cannot detect whether it will be allowed to autoplay or whether that autoplay will be blocked until it calls play on the media element. ## Goal -A site should be able to determine whether a video will autoplay or not. Knowing this in advance is important for a site as they may want to adjust their user experience or select alternate content to use instead. + +A site should be able to determine whether a video will autoplay or not. Knowing this in advance is important for a site as it may want to adjust the user experience or select alternate content to use instead. ## Proposed API Design + The document has an autoplay policy which can change. There will be an API on the document to get the autoplay policy and another on the media element which will return a boolean as to whether the media will be able to autoplay. There are three types of autoplay policy: @@ -24,19 +27,18 @@ enum AutoplayPolicy { "disallowed" }; -partial interface Document { - Promise getAutoplayPolicy(); +enum AutoplayPolicyMediaType { + "mediaelement", + "audiocontext" }; -partial interface HTMLMediaElement { - Promise canAutoplay(); +partial interface Navigator { + AutoplayPolicy getAutoplayPolicy(AutoplayPolicyMediaType type); + AutoplayPolicy getAutoplayPolicy(HTMLMediaElement element); + AutoplayPolicy getAutoplayPolicy(AudioContext context); }; ``` -The API should be async because determining whether a site can autoplay can require cross-process communications to gather data such as website settings or user preferences. In this design the browser does not need to calculate the autoplay policy until getAutoplayPolicy is called. Being async also does not limit browser implementations of what determines autoplay policy. - -**There is strong disagreement over whether this API should be async or sync. For more details about the pros/cons please see this issue: https://github.com/WICG/autoplay/issues/7** - ## Sample Code ### A site would like to change the source based on whether it will autoplay @@ -44,9 +46,9 @@ The API should be async because determining whether a site can autoplay can requ In this situation a site would like to change the source based on whether it will autoplay. In this example the site will play `video.webm` if it can autoplay unmuted. If it cannot then it will use `video-alt.webm` instead. ```javascript -let policy = await document.getAutoplayPolicy(); +const policy = navigator.getAutoplayPolicy("mediaelement"); -if (policy == "allowed") { +if (policy === "allowed") { loadUnmutedVideo(); } else { loadMutedVideo(); @@ -58,59 +60,29 @@ if (policy == "allowed") { In this situation a site would like to change its experience based on whether it will autoplay. In this example if it cannot autoplay unmuted then it will mute the video element. ```javascript -let policy = await document.getAutoplayPolicy(); +const video = document.getElementById("video"); +const policy = navigator.getAutoplayPolicy("mediaelement"); video.src = "video.webm"; -video.muted = !await video.canAutoplay(); -video.play(); -``` - -## Open questions - -### Sync vs Async - -There is a strong disagreement about whether this API should be synchronous instead (the sync design is supported by both Apple and Mozilla). However, it would require all browsers to always be able to answer whether a website can autoplay at load time; regardless of their autoplay policies. - -The synchronous API would be designed like this: - -```javascript -partial interface Document { - readonly attribute AutoplayPolicy autoplayPolicy; - attribute EventHandler onautoplaypolicychange; -}; -partial interface HTMLMediaElement { - readonly boolean canAutoplay; -}; -``` - -The first example from above using this design would be as follows: - -```javascript -if (document.autoplayPolicy == "allowed") { - loadUnmutedVideo(); -} else { - loadMutedVideo(); +if (policy === "allow-muted") { + video.muted = true; } -``` - -The second example from above using this design would be as follows: -```javascript -video.src = "video.webm"; -video.muted = !video.canAutoplay; video.play(); ``` -### Event Listener Issue +## Alternatives Considered + +### Event Listener We considered having an event listener to allow sites to listen to changes in autoplay policy. However, this may cause issues where there are multiple event listeners on a page that all start playing when the autoplay policy changes. ### Autoplay Permission -We considered having autoplay as a permission. However, there are a few differences between the autoplay and permissions: +We considered having autoplay as a permission. However, there are a few differences between the autoplay policy and permissions: - * Autoplay is something that is applied to the site from the browser; rather than something that should be requested - * Autoplay has multiple states (e.g. allowed, allowed-muted); rather than a yes or no - * Autoplay is not implemented by the user agents as a permission + * Autoplay policy is something that is applied to the site from the browser; rather than something that should be requested + * Autoplay policy has multiple states (e.g. allowed, allowed-muted); rather than a yes or no + * Autoplay policy is not implemented by user agents as a permission * Permissions are async