| OLD | NEW |
| 1 <html> | 1 <html> |
| 2 <video autoplay controls></video> | 2 <video autoplay controls></video> |
| 3 <script src=media-file.js></script> | 3 <script src=media-file.js></script> |
| 4 <!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956 | 4 <!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956 |
| 5 (Please avoid writing new tests using video-test.js) --> | 5 (Please avoid writing new tests using video-test.js) --> |
| 6 <script src=video-test.js></script> | 6 <script src=video-test.js></script> |
| 7 <script src=autoplay-experiment-helper.js></script> |
| 7 <body> | 8 <body> |
| 8 <pre> | 9 <pre> |
| 9 Check if the autoplay gesture override experiment works. There are a lot | 10 Check if the autoplay gesture override experiment works. There are a lot |
| 10 of config options, so this test just runs all of them. | 11 of config options, so this test just runs all of them. |
| 11 | 12 |
| 12 The "results" table contains one row per config tested. | 13 The "results" table contains one row per config tested. |
| 13 == Test Inputs == | 14 == Test Inputs == |
| 14 # - config number, in case you'd like to run just one. | 15 # - config number, in case you'd like to run just one. |
| 15 Flags - autoplay experiment setting being tested. | 16 Flags - autoplay experiment setting being tested. |
| 16 a - "foraudio" | 17 a - "foraudio" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 33 yes - muted attribute is set on the element. | 34 yes - muted attribute is set on the element. |
| 34 Mobile - is page optimized for mobile? | 35 Mobile - is page optimized for mobile? |
| 35 no - page is not optimized for mobile. | 36 no - page is not optimized for mobile. |
| 36 yes - page is optimized for mobile. | 37 yes - page is optimized for mobile. |
| 37 View - is media in viewport? | 38 View - is media in viewport? |
| 38 onscreen - element starts out onscreen. | 39 onscreen - element starts out onscreen. |
| 39 scroll - element starts offscreen, scrolled into view once | 40 scroll - element starts offscreen, scrolled into view once |
| 40 it is ready to play. | 41 it is ready to play. |
| 41 offscreen - element starts out offscreen and stays offscreen. | 42 offscreen - element starts out offscreen and stays offscreen. |
| 42 obscured - onscreen but page is not visible. | 43 obscured - onscreen but page is not visible. |
| 44 Setting - autoplay settings value |
| 45 enabled - content settings enables autoplay |
| 46 disabled - content settings disables autoplay |
| 43 | 47 |
| 44 == Test Outputs == | 48 == Test Outputs == |
| 45 Early? - did playback start before element was scrolled onscreen? For | 49 Early? - did playback start before element was scrolled onscreen? For |
| 46 tests in which View!=scroll, this is reported as "-". | 50 tests in which View!=scroll, this is reported as "-". |
| 47 Played? - did playback start by the conclusion of the test? | 51 Played? - did playback start by the conclusion of the test? |
| 48 Muted? - was the media muted? If the media didn't play, then this is | 52 Muted? - was the media muted? If the media didn't play, then this is |
| 49 reported as "-". | 53 reported as "-". |
| 50 | 54 |
| 51 </pre> | 55 </pre> |
| 52 <table id="results"> | 56 <table id="results"> |
| 53 <tr> | 57 <tr> |
| 54 <td>#</td> | 58 <td>#</td> |
| 55 <td>Flags</td> | 59 <td>Flags</td> |
| 56 <td>Type</td> | 60 <td>Type</td> |
| 57 <td>Play w/</td> | 61 <td>Play w/</td> |
| 58 <td>Mute</td> | 62 <td>Mute</td> |
| 59 <td>Mobile</td> | 63 <td>Mobile</td> |
| 60 <td>View</td> | 64 <td>View</td> |
| 65 <td>Setting</td> |
| 61 <td>Early?</td> | 66 <td>Early?</td> |
| 62 <td>Played?</td> | 67 <td>Played?</td> |
| 63 <td>Muted?</td> | 68 <td>Muted?</td> |
| 64 </tr> | 69 </tr> |
| 65 </table> | 70 </table> |
| 66 </body> | 71 </body> |
| 67 | 72 |
| 68 <script> | 73 <script> |
| 69 | 74 |
| 70 // Starting configuration number. This should be zero normally. | 75 start('video', [ 'none', |
| 71 var configNumber = 0; | 76 'enabled-forvideo', |
| 72 | 77 'enabled-forvideo-ifpagevisible', |
| 73 var mediaFile = findMediaFile("video", "content/test"); | 78 'enabled-forvideo-ifviewport-ifmuted', |
| 74 var onscreenParent = document.createElement("div"); | 79 'enabled-forvideo-ifviewport-playmuted', |
| 75 // The onscreen parent's height is also used to make sure that the off-screen | 80 'enabled-forvideo-ifmobile', |
| 76 // parent is, in fact, off-screen. | 81 'enabled-foraudio']); |
| 77 onscreenParent.style.height = "1000px"; | |
| 78 document.body.insertBefore(onscreenParent, document.body.firstChild); | |
| 79 // Is the page optimized for mobile? We can't un-optimize it. | |
| 80 var isOptimizedForMobile = false; | |
| 81 // Also create another root that's off the bottom of the window. | |
| 82 var offscreenParent = document.createElement("div"); | |
| 83 document.body.appendChild(offscreenParent); | |
| 84 | |
| 85 function didPlaybackStart(element) | |
| 86 { | |
| 87 return !element.paused || element.ended; | |
| 88 } | |
| 89 | |
| 90 function becomeOptimizedForMobile(enable) | |
| 91 { | |
| 92 // If we're in the right state already, then return; | |
| 93 if (enable == isOptimizedForMobile) | |
| 94 return; | |
| 95 | |
| 96 if (!enable) { | |
| 97 // We can't transition out of optimized for mobile. | |
| 98 console.log("becomeOptimizedForMobile: test is broken -- cannot un-enabl
e mobile"); | |
| 99 endTest(); | |
| 100 } else { | |
| 101 // This only works once. | |
| 102 mobileMetaTag = document.createElement('meta'); | |
| 103 mobileMetaTag.name = "viewport"; | |
| 104 mobileMetaTag.content = "width=device-width"; | |
| 105 document.head.appendChild(mobileMetaTag); | |
| 106 isOptimizedForMobile = true; | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 function addResultsRow(spec) | |
| 111 { | |
| 112 // Add a row to the results table. | |
| 113 var row = document.getElementById("results").insertRow(); | |
| 114 var td = row.insertCell(); | |
| 115 | |
| 116 // Add experiment number | |
| 117 row.insertCell().innerText = (""+spec.experimentNumber); | |
| 118 | |
| 119 // Process experiment type specially. | |
| 120 var type = spec.experimentType; | |
| 121 var smallType = ""; | |
| 122 smallType += type.includes("-forvideo")?"v":""; | |
| 123 smallType += type.includes("-foraudio")?"a":""; | |
| 124 smallType += type.includes("-ifviewport")?"V":""; | |
| 125 smallType += type.includes("-ifpagevisible")?"P":""; | |
| 126 smallType += type.includes("-ifmuted")?"M":""; | |
| 127 smallType += type.includes("-playmuted")?"p":""; | |
| 128 smallType += type.includes("-ifmobile")?"m":""; | |
| 129 row.insertCell().innerText = smallType; | |
| 130 | |
| 131 // Add remaining fields. | |
| 132 var fields = [ "elementType", "autoplayType", "mutedType", "mobileType", | |
| 133 "visType", "playedEarly", "played", "muted"]; | |
| 134 for(idx in fields) | |
| 135 row.insertCell().innerText = spec[fields[idx]].substring(0,7); | |
| 136 } | |
| 137 | |
| 138 function configureElementViaScript(element, spec) | |
| 139 { | |
| 140 if(spec.autoplayType == "play()") | |
| 141 element.play(); | |
| 142 } | |
| 143 | |
| 144 function queueNextExperiment() | |
| 145 { | |
| 146 // Start the next config, but let the event queue drain. | |
| 147 setTimeout(runNextConfig, 0); | |
| 148 } | |
| 149 | |
| 150 function checkElementStatus(element) | |
| 151 { | |
| 152 // Update the spec with the results. | |
| 153 var didStart = didPlaybackStart(element); | |
| 154 element.spec.played = didStart ? "played" : "no"; | |
| 155 element.spec.muted = didStart ? (element.muted ? "muted" : "unmuted") : "-"; | |
| 156 | |
| 157 addResultsRow(element.spec); | |
| 158 element.remove(); | |
| 159 | |
| 160 // Scroll back to the top, in case this was a scrolling test. | |
| 161 onscreenParent.scrollIntoView(); | |
| 162 | |
| 163 // Also make sure that the page is visible again. Hidden pages cause the | |
| 164 // test to proceed very slowly. | |
| 165 testRunner.setPageVisibility("visible"); | |
| 166 | |
| 167 queueNextExperiment(); | |
| 168 } | |
| 169 | |
| 170 function runOneConfig(spec) | |
| 171 { | |
| 172 internals.settings.setAutoplayExperimentMode(spec.experimentType); | |
| 173 internals.settings.setViewportMetaEnabled(true); | |
| 174 | |
| 175 // Create, configure, and attach a media element. | |
| 176 var element = document.createElement(spec.elementType); | |
| 177 element.controls = true; | |
| 178 | |
| 179 // Hide or show the page. | |
| 180 if (spec.visType == "obscured") | |
| 181 testRunner.setPageVisibility("hidden"); | |
| 182 | |
| 183 // Pick whether the element will be visible when canPlayThrough. | |
| 184 if (spec.visType == "offscreen" || spec.visType == "scroll") | |
| 185 offscreenParent.appendChild(element); | |
| 186 else | |
| 187 onscreenParent.appendChild(element); | |
| 188 | |
| 189 // Set any attributes before canPlayThrough. | |
| 190 if (spec.mutedType == "yes") | |
| 191 element.muted = true; | |
| 192 if (spec.autoplayType == "attr") | |
| 193 element.autoplay = true; | |
| 194 | |
| 195 becomeOptimizedForMobile(spec.mobileType == "yes"); | |
| 196 | |
| 197 spec.playedEarly = "-"; | |
| 198 | |
| 199 // Record the spec in the element, so that we can display the | |
| 200 // results later. | |
| 201 element.spec = spec; | |
| 202 window.internals.triggerAutoplayViewportCheck(element); | |
| 203 | |
| 204 // Wait for canplaythrough before continuing, so that the media | |
| 205 // might actually be playing. | |
| 206 element.addEventListener("canplaythrough", function() | |
| 207 { | |
| 208 // Now that we can play, if we're supposed to play / mute via js do so. | |
| 209 configureElementViaScript(element, spec); | |
| 210 | |
| 211 // If we're supposed to scroll the item onscreen after it is ready to | |
| 212 // play, then do so now. | |
| 213 if(spec.visType == "scroll") { | |
| 214 // Record the play state here, too, before we scroll. | |
| 215 spec.playedEarly = didPlaybackStart(element) ? "yes" : "no"; | |
| 216 | |
| 217 // We are supposed to scroll the player into view. | |
| 218 element.scrollIntoView(true); | |
| 219 // TODO(liberato): remove once autoplay gesture override experiment
concludes. | |
| 220 window.internals.triggerAutoplayViewportCheck(element); | |
| 221 // Once these two methods return, changes to the element state due | |
| 222 // to the autoplay experiment should be observable synchronously. | |
| 223 checkElementStatus(element, spec); | |
| 224 } else { | |
| 225 // Record the results immediately. | |
| 226 checkElementStatus(element, spec); | |
| 227 } | |
| 228 }); | |
| 229 | |
| 230 // Set the source, which will eventually lead to canPlayThrough. | |
| 231 element.src = mediaFile; | |
| 232 } | |
| 233 | |
| 234 var experimentTypes = [ | |
| 235 "none", | |
| 236 "enabled-forvideo", | |
| 237 "enabled-forvideo-ifpagevisible", | |
| 238 "enabled-forvideo-ifviewport", | |
| 239 "enabled-forvideo-ifviewport-ifmuted", | |
| 240 "enabled-forvideo-ifviewport-playmuted", | |
| 241 "enabled-foraudio", | |
| 242 "enabled-forvideo-ifmobile", | |
| 243 "enabled-foraudio-ifviewport", | |
| 244 ]; | |
| 245 var elementTypes = ["video", "audio"]; | |
| 246 var autoplayTypes = ["none", "attr", "play()"]; | |
| 247 var mutedTypes = ["no", "yes"]; | |
| 248 var visTypes = ["onscreen", "scroll", "offscreen", "obscured"]; | |
| 249 // mobileTypes must always start with no, since we cannot un-optimize the page. | |
| 250 var mobileTypes = ["no", "yes"]; | |
| 251 | |
| 252 function runNextConfig() | |
| 253 { | |
| 254 // Convert configNumber into a spec, and run it. | |
| 255 var exp = configNumber; | |
| 256 | |
| 257 // Convert this experiment number into settings. | |
| 258 var spec = {}; | |
| 259 spec.elementType = elementTypes[exp % elementTypes.length]; | |
| 260 exp = Math.floor(exp / elementTypes.length); | |
| 261 spec.experimentType = experimentTypes[exp % experimentTypes.length]; | |
| 262 exp = Math.floor(exp / experimentTypes.length); | |
| 263 spec.autoplayType = autoplayTypes[exp % autoplayTypes.length]; | |
| 264 exp = Math.floor(exp / autoplayTypes.length); | |
| 265 spec.mutedType = mutedTypes[exp % mutedTypes.length]; | |
| 266 exp = Math.floor(exp / mutedTypes.length); | |
| 267 spec.visType = visTypes[exp % visTypes.length]; | |
| 268 exp = Math.floor(exp / visTypes.length); | |
| 269 // Mobile must always change last, so that all the "no" cases precede | |
| 270 // all the "yes" cases, since we can't switch the doc back to "not | |
| 271 // optimized for mobile". | |
| 272 spec.mobileType = mobileTypes[exp % mobileTypes.length]; | |
| 273 exp = Math.floor(exp / mobileTypes.length); | |
| 274 spec.experimentNumber = configNumber; | |
| 275 | |
| 276 // Return null if configNumber was larger than the highest experiment. | |
| 277 if (exp > 0) | |
| 278 endTest(); | |
| 279 | |
| 280 configNumber++; | |
| 281 | |
| 282 // To keep the test fast, skip a few combinations. | |
| 283 var skip = false; | |
| 284 if (!spec.experimentType.includes("-ifmuted") && spec.mutedType != "no") | |
| 285 skip = true; | |
| 286 | |
| 287 // Only allow basic combinations for the mobile case. We just want to | |
| 288 // test video with autoplay, no mute options when testing -ifmobile. | |
| 289 // Similarly, if we're setting the page to be optimied for mobile, then | |
| 290 // require that we're one of those tests. | |
| 291 if ((spec.mobileType == "yes" || spec.experimentType.includes("-ifmobile")) | |
| 292 && (spec.elementType != "video" || spec.autoplayType != "attr" | |
| 293 || spec.mutedType != "no" | |
| 294 || spec.visType != "onscreen" | |
| 295 || (spec.experimentType != "enabled-forvideo" | |
| 296 && spec.experimentType != "enabled-forvideo-ifmobile"))) | |
| 297 skip = true; | |
| 298 | |
| 299 var mismatched =(spec.elementType == "video" | |
| 300 && spec.experimentType.includes("-foraudio")) | |
| 301 || (spec.elementType == "audio" | |
| 302 && spec.experimentType.includes("-forvideo")); | |
| 303 | |
| 304 if (spec.autoplayType == "none" && spec.visType != 'onscreen') | |
| 305 skip = true; | |
| 306 else if (spec.experimentType.includes("-ifmuted") | |
| 307 && spec.visType != "onscreen") | |
| 308 skip = true; | |
| 309 else if (spec.visType == "offscreen" | |
| 310 && spec.autoplayType != "attr") | |
| 311 skip = true; | |
| 312 else if (!spec.experimentType.includes("-ifmuted") | |
| 313 && spec.mutedType == "yes") | |
| 314 skip = true; | |
| 315 else if (spec.elementType == "audio" && spec.mutedType == "yes") | |
| 316 skip = true; | |
| 317 else if (spec.elementType == "audio" && spec.visType != "scroll") | |
| 318 skip = true; | |
| 319 else if (mismatched && spec.visType !="onscreen") | |
| 320 skip = true; | |
| 321 else if (mismatched && spec.autoplayType != "attr") | |
| 322 skip = true; | |
| 323 else if (spec.visType == "obscured" | |
| 324 && !spec.experimentType.includes("-ifpagevisible")) | |
| 325 skip = true; | |
| 326 else if ((spec.visType == "offscreen" || spec.visType == "scroll" | |
| 327 || spec.autoplayType != "attr" || spec.elementType != "video") | |
| 328 && spec.experimentType.includes("-ifpagevisible")) | |
| 329 skip = true; | |
| 330 | |
| 331 if (skip) | |
| 332 queueNextExperiment(); | |
| 333 else | |
| 334 runOneConfig(spec); | |
| 335 } | |
| 336 | |
| 337 window.internals.settings.setMediaPlaybackRequiresUserGesture(true); | |
| 338 runNextConfig(); | |
| 339 | 82 |
| 340 </script> | 83 </script> |
| 341 </html> | 84 </html> |
| OLD | NEW |