| OLD | NEW |
| 1 <video autoplay controls></video> | 1 <video autoplay controls></video> |
| 2 <script src=media-file.js></script> | 2 <script src=media-file.js></script> |
| 3 <script src=video-test.js></script> | 3 <script src=video-test.js></script> |
| 4 <body> | 4 <body> |
| 5 <pre> | 5 <pre> |
| 6 Check if the autoplay gesture override experiment works. There are a lot | 6 Check if the autoplay gesture override experiment works. There are a lot |
| 7 of config options, so this test just runs all of them. | 7 of config options, so this test just runs all of them. |
| 8 | 8 |
| 9 The "results" table contains one row per config tested. | 9 The "results" table contains one row per config tested. |
| 10 == Test Inputs == | 10 == Test Inputs == |
| 11 # - config number, in case you'd like to run just one. | 11 # - config number, in case you'd like to run just one. |
| 12 Flags - autoplay experiment setting being tested. | 12 Flags - autoplay experiment setting being tested. |
| 13 a - "foraudio" | 13 a - "foraudio" |
| 14 v - "forvideo" | 14 v - "forvideo" |
| 15 V - "ifviewport" |
| 15 M - "ifmuted" | 16 M - "ifmuted" |
| 16 p - "playmuted" | 17 p - "playmuted" |
| 17 For example, EM means "enabled-ifmuted". | 18 For example, vM means '-forvideo-ifmuted". |
| 18 This test does not check -ifmobile since that check always | 19 This test does not check -ifmobile since that check always |
| 19 fails outside of android. | 20 fails outside of android. |
| 20 Type - audio or video element? | 21 Type - audio or video element? |
| 21 audio - <audio> | 22 audio - <audio> |
| 22 video - <video> | 23 video - <video> |
| 23 Play w/- how is play requested? | 24 Play w/- how is play requested? |
| 24 none - play is not requested. | 25 none - play is not requested. |
| 25 attr - autoplay attribute is set on the element. | 26 attr - autoplay attribute is set on the element. |
| 26 play() - play() called after media is ready to play. | 27 play() - play() called after media is ready to play. |
| 27 Mute - how is media muted? | 28 Mute - how is media muted? |
| 28 none - media is not muted. | 29 none - media is not muted. |
| 29 attr - muted attribute is set on the element. | 30 attr - muted attribute is set on the element. |
| 30 js - muted property is set after media is ready to play. | 31 js - muted property is set after media is ready to play. |
| 32 View - is media in viewport? |
| 33 onscreen - element starts out onscreen. |
| 34 scroll - element starts offscreen, scrolled into view once |
| 35 it is ready to play. |
| 36 offscreen - element starts out offscreen and stays offscreen. |
| 31 | 37 |
| 32 == Test Outputs == | 38 == Test Outputs == |
| 39 Early? - did playback start before element was scrolled onscreen? For |
| 40 tests in which View!=scroll, this is reported as "-". |
| 33 Played? - did playback start by the conclusion of the test? | 41 Played? - did playback start by the conclusion of the test? |
| 34 Muted? - was the media muted? If the media didn't play, then this is | 42 Muted? - was the media muted? If the media didn't play, then this is |
| 35 reported as "-". | 43 reported as "-". |
| 36 | 44 |
| 37 </pre> | 45 </pre> |
| 38 <table id="results"> | 46 <table id="results"> |
| 39 <tr> | 47 <tr> |
| 40 <td>#</td> | 48 <td>#</td> |
| 41 <td>Flags</td> | 49 <td>Flags</td> |
| 42 <td>Type</td> | 50 <td>Type</td> |
| 43 <td>Play w/</td> | 51 <td>Play w/</td> |
| 44 <td>Mute</td> | 52 <td>Mute</td> |
| 53 <td>View</td> |
| 54 <td>Early?</td> |
| 45 <td>Played?</td> | 55 <td>Played?</td> |
| 46 <td>Muted?</td> | 56 <td>Muted?</td> |
| 47 </tr> | 57 </tr> |
| 48 </table> | 58 </table> |
| 49 </body> | 59 </body> |
| 50 | 60 |
| 51 <script> | 61 <script> |
| 52 | 62 |
| 53 // Starting configuration number. This should be zero normally. | 63 // Starting configuration number. This should be zero normally. |
| 54 var configNumber = 0; | 64 var configNumber = 0; |
| 55 | 65 |
| 56 var mediaFile = findMediaFile("video", "content/test"); | 66 var mediaFile = findMediaFile("video", "content/test"); |
| 57 var onscreenParent = document.createElement("div"); | 67 var onscreenParent = document.createElement("div"); |
| 68 // The onscreen parent's height is also used to make sure that the off-screen |
| 69 // parent is, in fact, off-screen. |
| 70 onscreenParent.style.height="1000px"; |
| 58 document.body.insertBefore(onscreenParent, document.body.firstChild); | 71 document.body.insertBefore(onscreenParent, document.body.firstChild); |
| 72 // Also create another root that's off the bottom of the window. |
| 73 var offscreenParent = document.createElement("div"); |
| 74 document.body.appendChild(offscreenParent); |
| 59 | 75 |
| 60 function didPlaybackStart(video) | 76 function didPlaybackStart(element) |
| 61 { | 77 { |
| 62 // We say that the video started if it's not paused or if it played and | 78 // We say that the element started if it's not paused or if it played and |
| 63 // already ended. | 79 // already ended. |
| 64 return !video.paused || video.ended; | 80 return !element.paused || element.ended; |
| 65 } | 81 } |
| 66 | 82 |
| 67 function addResultsRow(spec) | 83 function addResultsRow(spec) |
| 68 { | 84 { |
| 69 // Add a row to the results table. | 85 // Add a row to the results table. |
| 70 var row = document.getElementById("results").insertRow(-1); | 86 var row = document.getElementById("results").insertRow(-1); |
| 71 var td = row.insertCell(0); | 87 var td = row.insertCell(0); |
| 72 | 88 |
| 73 // Add experiment number | 89 // Add experiment number |
| 74 row.insertCell(-1).innerText = (""+spec["experimentNumber"]); | 90 row.insertCell(-1).innerText = (""+spec["experimentNumber"]); |
| 75 | 91 |
| 76 // Process experiment type specially. | 92 // Process experiment type specially. |
| 77 var type = spec["experimentType"]; | 93 var type = spec["experimentType"]; |
| 78 var smallType = ""; | 94 var smallType = ""; |
| 79 smallType += (type.indexOf("-forvideo")>-1)?"v":""; | 95 smallType += (type.indexOf("-forvideo")>-1)?"v":""; |
| 80 smallType += (type.indexOf("-foraudio")>-1)?"a":""; | 96 smallType += (type.indexOf("-foraudio")>-1)?"a":""; |
| 97 smallType += (type.indexOf("-ifviewport")>-1)?"V":""; |
| 81 smallType += (type.indexOf("-ifmuted")>-1)?"M":""; | 98 smallType += (type.indexOf("-ifmuted")>-1)?"M":""; |
| 82 smallType += (type.indexOf("-playmuted")>-1)?"p":""; | 99 smallType += (type.indexOf("-playmuted")>-1)?"p":""; |
| 83 row.insertCell(-1).innerText = smallType; | 100 row.insertCell(-1).innerText = smallType; |
| 84 | 101 |
| 85 // Add remaining fields. | 102 // Add remaining fields. |
| 86 var fields = [ "elementType", "autoplayType", "mutedType", "played", | 103 var fields = [ "elementType", "autoplayType", "mutedType", "visType", |
| 87 "muted"]; | 104 "playedEarly", "played", "muted"]; |
| 88 for(idx in fields) | 105 for(idx in fields) |
| 89 row.insertCell(-1).innerText = spec[fields[idx]].substring(0,7); | 106 row.insertCell(-1).innerText = spec[fields[idx]].substring(0,7); |
| 90 } | 107 } |
| 91 | 108 |
| 92 function configureVideoViaScript(element, spec) | 109 function configureElementViaScript(element, spec) |
| 93 { | 110 { |
| 94 if (spec.mutedType == "js") | 111 if (spec.mutedType == "js") |
| 95 element.muted = true; | 112 element.muted = true; |
| 96 if(spec.autoplayType == "play()") | 113 if(spec.autoplayType == "play()") |
| 97 element.play(); | 114 element.play(); |
| 98 } | 115 } |
| 99 | 116 |
| 100 function queueNextExperiment() | 117 function queueNextExperiment() |
| 101 { | 118 { |
| 102 // Start the next config, but let the event queue drain. | 119 // Start the next config, but let the event queue drain. |
| 103 setTimeout(runNextConfig, 0); | 120 setTimeout(runNextConfig, 0); |
| 104 } | 121 } |
| 105 | 122 |
| 106 function checkElementStatus(element) | 123 function checkElementStatus(element) |
| 107 { | 124 { |
| 108 // Update the spec with the results. | 125 // Update the spec with the results. |
| 109 var didStart = didPlaybackStart(element); | 126 var didStart = didPlaybackStart(element); |
| 110 element.spec.played = didStart ? "played" : "no"; | 127 element.spec.played = didStart ? "played" : "no"; |
| 111 element.spec.muted = didStart ? (element.muted ? "muted" : "unmuted") : "-"; | 128 element.spec.muted = didStart ? (element.muted ? "muted" : "unmuted") : "-"; |
| 112 | 129 |
| 113 addResultsRow(element.spec); | 130 addResultsRow(element.spec); |
| 114 element.parentElement.removeChild(element); | 131 element.parentElement.removeChild(element); |
| 115 | 132 |
| 133 // Scroll back to the top, in case this was a scrolling test. |
| 134 onscreenParent.scrollIntoView(); |
| 135 |
| 116 queueNextExperiment(); | 136 queueNextExperiment(); |
| 117 } | 137 } |
| 118 | 138 |
| 119 function runOneConfig(spec) | 139 function runOneConfig(spec) |
| 120 { | 140 { |
| 121 internals.settings.setAutoplayExperimentMode(spec.experimentType); | 141 internals.settings.setAutoplayExperimentMode(spec.experimentType); |
| 122 | 142 |
| 123 // Create, configure, and attach a media element. | 143 // Create, configure, and attach a media element. |
| 124 var element = document.createElement(spec.elementType); | 144 var element = document.createElement(spec.elementType); |
| 145 element.setAttribute("controls", "true"); |
| 125 | 146 |
| 126 onscreenParent.appendChild(element); | 147 // Pick whether the element will be visible when canPlayThrough. |
| 148 if (spec.visType == "onscreen") |
| 149 onscreenParent.appendChild(element); |
| 150 else |
| 151 offscreenParent.appendChild(element); |
| 127 | 152 |
| 128 // Set any attributes before canPlayThrough. | 153 // Set any attributes before canPlayThrough. |
| 129 if (spec.mutedType == "attr") | 154 if (spec.mutedType == "attr") |
| 130 element.setAttribute("muted", "true"); | 155 element.setAttribute("muted", "true"); |
| 131 if (spec.autoplayType == "attr") | 156 if (spec.autoplayType == "attr") |
| 132 element.setAttribute("autoplay", "true"); | 157 element.setAttribute("autoplay", "true"); |
| 133 | 158 |
| 159 spec.playedEarly = "-"; |
| 160 |
| 134 // Record the spec in the element, so that we can display the | 161 // Record the spec in the element, so that we can display the |
| 135 // results later. | 162 // results later. |
| 136 element.spec = spec; | 163 element.spec = spec; |
| 137 | 164 |
| 138 // Wait for canplaythrough before continuing, so that the media | 165 // Wait for canplaythrough before continuing, so that the media |
| 139 // might actually be playing. | 166 // might actually be playing. |
| 140 element.addEventListener("canplaythrough", function() | 167 element.addEventListener("canplaythrough", function() |
| 141 { | 168 { |
| 142 // Now that we can play, if we're supposed to play / mute via js do so. | 169 // Now that we can play, if we're supposed to play / mute via js do so. |
| 143 configureVideoViaScript(element, spec); | 170 configureElementViaScript(element, spec); |
| 144 | 171 |
| 145 // Record the results. | 172 // If we're supposed to scroll the item onscreen after it is ready to |
| 146 checkElementStatus(element); | 173 // play, then do so now. |
| 174 if(spec.visType == "scroll") { |
| 175 // Record the play state here, too, before we scroll. |
| 176 spec.playedEarly = didPlaybackStart(element) ? "yes" : "no"; |
| 177 |
| 178 // We are supposed to scroll the player into view. |
| 179 element.scrollIntoView(true); |
| 180 // We cause two visibility checks. The first notices the scroll, |
| 181 // while the second notices that scrolling has stopped. |
| 182 // It would be nicer to trigger location polling here, but that |
| 183 // can take ~second to notice that scrolling is stopped. |
| 184 window.internals.triggerAutoplayViewportCheck(element); |
| 185 window.internals.triggerAutoplayViewportCheck(element); |
| 186 // Once those are return, the state should be correct. |
| 187 checkElementStatus(element, spec); |
| 188 } else { |
| 189 // Record the results immediately. |
| 190 checkElementStatus(element, spec); |
| 191 } |
| 147 }); | 192 }); |
| 148 | 193 |
| 149 // Set the source, which will eventually lead to canPlayThrough. | 194 // Set the source, which will eventually lead to canPlayThrough. |
| 150 element.src=mediaFile; | 195 element.src=mediaFile; |
| 151 } | 196 } |
| 152 | 197 |
| 153 var experimentTypes = [ | 198 var experimentTypes = [ |
| 154 "none", | 199 "none", |
| 155 "enabled-forvideo", | 200 "enabled-forvideo", |
| 156 "enabled-forvideo-ifmuted", | 201 "enabled-forvideo-ifviewport", |
| 157 "enabled-forvideo-playmuted", | 202 "enabled-forvideo-ifviewport-ifmuted", |
| 203 "enabled-forvideo-ifviewport-playmuted", |
| 158 "enabled-foraudio", | 204 "enabled-foraudio", |
| 205 "enabled-foraudio-ifviewport", |
| 159 ]; | 206 ]; |
| 160 var elementTypes = ["video", "audio"]; | 207 var elementTypes = ["video", "audio"]; |
| 161 var autoplayTypes = ["none", "attr", "play()"]; | 208 var autoplayTypes = ["none", "attr", "play()"]; |
| 162 var mutedTypes = ["none", "attr", "js"]; | 209 var mutedTypes = ["none", "attr", "js"]; |
| 210 var visTypes = ["onscreen", "scroll", "offscreen"]; |
| 163 | 211 |
| 164 function runNextConfig() | 212 function runNextConfig() |
| 165 { | 213 { |
| 166 // Convert configNumber into a spec, and run it. | 214 // Convert configNumber into a spec, and run it. |
| 167 var exp = configNumber; | 215 var exp = configNumber; |
| 168 | 216 |
| 169 // Convert this experiment number into settings. | 217 // Convert this experiment number into settings. |
| 170 var spec = {}; | 218 var spec = {}; |
| 171 spec.elementType = elementTypes[exp % elementTypes.length]; | 219 spec.elementType = elementTypes[exp % elementTypes.length]; |
| 172 exp = Math.floor(exp / elementTypes.length); | 220 exp = Math.floor(exp / elementTypes.length); |
| 173 spec.experimentType = experimentTypes[exp % experimentTypes.length]; | 221 spec.experimentType = experimentTypes[exp % experimentTypes.length]; |
| 174 exp = Math.floor(exp / experimentTypes.length); | 222 exp = Math.floor(exp / experimentTypes.length); |
| 175 spec.autoplayType = autoplayTypes[exp % autoplayTypes.length]; | 223 spec.autoplayType = autoplayTypes[exp % autoplayTypes.length]; |
| 176 exp = Math.floor(exp / autoplayTypes.length); | 224 exp = Math.floor(exp / autoplayTypes.length); |
| 177 spec.mutedType = mutedTypes[exp % mutedTypes.length]; | 225 spec.mutedType = mutedTypes[exp % mutedTypes.length]; |
| 178 exp = Math.floor(exp / mutedTypes.length); | 226 exp = Math.floor(exp / mutedTypes.length); |
| 227 spec.visType = visTypes[exp % visTypes.length]; |
| 228 exp = Math.floor(exp / visTypes.length); |
| 179 spec.experimentNumber = configNumber; | 229 spec.experimentNumber = configNumber; |
| 180 | 230 |
| 181 // exp>0 here indicates that we've wrapped around. | 231 // exp>0 here indicates that we've wrapped around. |
| 182 if (exp > 0) { | 232 if (exp > 0) { |
| 183 endTest(); | 233 endTest(); |
| 184 } | 234 } |
| 185 | 235 |
| 186 configNumber++; | 236 configNumber++; |
| 187 | 237 |
| 188 // To keep the test fast, skip a few combinations. | 238 // To keep the test fast, skip a few combinations. |
| 189 var skip = false; | 239 var skip = false; |
| 190 if (spec.experimentType.indexOf("-ifmuted") == -1 && spec.mutedType != "none
") | 240 var mismatched =(spec.elementType == "video" |
| 241 && spec.experimentType.indexOf("-foraudio") > -1) |
| 242 || (spec.elementType == "audio" |
| 243 && spec.experimentType.indexOf("-forvideo") > -1); |
| 244 |
| 245 if (spec.autoplayType == "none" && spec.visType != 'onscreen') |
| 246 skip = true; |
| 247 else if (spec.experimentType.indexOf("-ifmuted") > -1 && spec.visType != "on
screen") |
| 248 skip = true; |
| 249 else if (spec.visType == "offscreen" && spec.autoplayType != "attr") |
| 250 skip = true; |
| 251 else if (spec.experimentType.indexOf("-ifmuted") == -1 && spec.mutedType !=
"none") |
| 252 skip = true; |
| 253 else if (spec.elementType == "audio" && spec.mutedType != "none") |
| 254 skip = true; |
| 255 else if (spec.elementType == "audio" && spec.visType != "scroll") |
| 256 skip = true; |
| 257 else if (mismatched && spec.visType !="onscreen") |
| 258 skip = true; |
| 259 else if (mismatched && spec.autoplayType != "attr") |
| 191 skip = true; | 260 skip = true; |
| 192 | 261 |
| 193 if (skip) | 262 if (skip) |
| 194 queueNextExperiment(); | 263 queueNextExperiment(); |
| 195 else | 264 else |
| 196 runOneConfig(spec); | 265 runOneConfig(spec); |
| 197 } | 266 } |
| 198 | 267 |
| 199 window.internals.settings.setMediaPlaybackRequiresUserGesture(true); | 268 window.internals.settings.setMediaPlaybackRequiresUserGesture(true); |
| 200 runNextConfig(); | 269 runNextConfig(); |
| 201 | 270 |
| 202 </script> | 271 </script> |
| OLD | NEW |