| OLD | NEW |
| (Empty) |
| 1 // Starting configuration number. This should be zero normally. | |
| 2 var configNumber = 0; | |
| 3 | |
| 4 var mediaFile = findMediaFile("video", "content/test"); | |
| 5 var onscreenParent = document.createElement("div"); | |
| 6 // The onscreen parent's height is also used to make sure that the off-screen | |
| 7 // parent is, in fact, off-screen. | |
| 8 onscreenParent.style.height = "1000px"; | |
| 9 document.body.insertBefore(onscreenParent, document.body.firstChild); | |
| 10 // Is the page optimized for mobile? We can't un-optimize it. | |
| 11 var isOptimizedForMobile = false; | |
| 12 // Also create another root that's off the bottom of the window. | |
| 13 var offscreenParent = document.createElement("div"); | |
| 14 document.body.appendChild(offscreenParent); | |
| 15 | |
| 16 function didPlaybackStart(element) | |
| 17 { | |
| 18 return !element.paused || element.ended; | |
| 19 } | |
| 20 | |
| 21 function becomeOptimizedForMobile(enable) | |
| 22 { | |
| 23 // If we're in the right state already, then return; | |
| 24 if (enable == isOptimizedForMobile) | |
| 25 return; | |
| 26 | |
| 27 if (!enable) { | |
| 28 // We can't transition out of optimized for mobile. | |
| 29 testRunner.notifyDone(); | |
| 30 } else { | |
| 31 // This only works once. | |
| 32 mobileMetaTag = document.createElement('meta'); | |
| 33 mobileMetaTag.name = "viewport"; | |
| 34 mobileMetaTag.content = "width=device-width"; | |
| 35 document.head.appendChild(mobileMetaTag); | |
| 36 isOptimizedForMobile = true; | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 function addResultsRow(spec) | |
| 41 { | |
| 42 // Add a row to the results table. | |
| 43 var row = document.getElementById("results").insertRow(); | |
| 44 var td = row.insertCell(); | |
| 45 | |
| 46 // Add experiment number | |
| 47 row.insertCell().innerText = (""+spec.experimentNumber); | |
| 48 | |
| 49 // Process experiment type specially. | |
| 50 var type = spec.experimentType; | |
| 51 var smallType = ""; | |
| 52 smallType += type.includes("-forvideo")?"v":""; | |
| 53 smallType += type.includes("-foraudio")?"a":""; | |
| 54 smallType += type.includes("-ifviewport")?"V":""; | |
| 55 smallType += type.includes("-ifpagevisible")?"P":""; | |
| 56 smallType += type.includes("-ifmuted")?"M":""; | |
| 57 smallType += type.includes("-playmuted")?"p":""; | |
| 58 smallType += type.includes("-ifmobile")?"m":""; | |
| 59 row.insertCell().innerText = smallType; | |
| 60 | |
| 61 // Add remaining fields. | |
| 62 var fields = [ "elementType", "autoplayType", "mutedType", "mobileType", | |
| 63 "visType", "settingValue", "playedEarly", "played", "muted"]; | |
| 64 for(idx in fields) | |
| 65 row.insertCell().innerText = spec[fields[idx]].substring(0,7); | |
| 66 } | |
| 67 | |
| 68 function configureElementViaScript(element, spec) | |
| 69 { | |
| 70 if(spec.autoplayType == "play()") | |
| 71 element.play(); | |
| 72 } | |
| 73 | |
| 74 function queueNextExperiment() | |
| 75 { | |
| 76 // Start the next config, but let the event queue drain. | |
| 77 setTimeout(runNextConfig, 0); | |
| 78 } | |
| 79 | |
| 80 function checkElementStatus(element) | |
| 81 { | |
| 82 // Update the spec with the results. | |
| 83 var didStart = didPlaybackStart(element); | |
| 84 element.spec.played = didStart ? "played" : "no"; | |
| 85 element.spec.muted = didStart ? (element.muted ? "muted" : "unmuted") : "-"; | |
| 86 | |
| 87 addResultsRow(element.spec); | |
| 88 element.remove(); | |
| 89 | |
| 90 // Scroll back to the top, in case this was a scrolling test. | |
| 91 onscreenParent.scrollIntoView(); | |
| 92 | |
| 93 // Also make sure that the page is visible again. Hidden pages cause the | |
| 94 // test to proceed very slowly. | |
| 95 testRunner.setPageVisibility("visible"); | |
| 96 | |
| 97 queueNextExperiment(); | |
| 98 } | |
| 99 | |
| 100 function runOneConfig(spec) | |
| 101 { | |
| 102 internals.settings.setAutoplayExperimentMode(spec.experimentType); | |
| 103 internals.settings.setViewportMetaEnabled(true); | |
| 104 testRunner.setAutoplayAllowed(spec.settingValue == "enabled"); | |
| 105 | |
| 106 // Create, configure, and attach a media element. | |
| 107 var element = document.createElement(spec.elementType); | |
| 108 element.controls = true; | |
| 109 | |
| 110 // Hide or show the page. | |
| 111 if (spec.visType == "obscured") | |
| 112 testRunner.setPageVisibility("hidden"); | |
| 113 | |
| 114 // Pick whether the element will be visible when canPlayThrough. | |
| 115 if (spec.visType == "offscreen" || spec.visType == "scroll") | |
| 116 offscreenParent.appendChild(element); | |
| 117 else | |
| 118 onscreenParent.appendChild(element); | |
| 119 | |
| 120 // Set any attributes before canPlayThrough. | |
| 121 if (spec.mutedType == "yes") | |
| 122 element.muted = true; | |
| 123 if (spec.autoplayType == "attr") | |
| 124 element.autoplay = true; | |
| 125 | |
| 126 becomeOptimizedForMobile(spec.mobileType == "yes"); | |
| 127 | |
| 128 spec.playedEarly = "-"; | |
| 129 | |
| 130 // Record the spec in the element, so that we can display the | |
| 131 // results later. | |
| 132 element.spec = spec; | |
| 133 internals.triggerAutoplayViewportCheck(element); | |
| 134 | |
| 135 // Wait for canplaythrough before continuing, so that the media | |
| 136 // might actually be playing. | |
| 137 element.addEventListener("canplaythrough", function() | |
| 138 { | |
| 139 // Now that we can play, if we're supposed to play / mute via js do so. | |
| 140 configureElementViaScript(element, spec); | |
| 141 | |
| 142 // If we're supposed to scroll the item onscreen after it is ready to | |
| 143 // play, then do so now. | |
| 144 if(spec.visType == "scroll") { | |
| 145 // Record the play state here, too, before we scroll. | |
| 146 spec.playedEarly = didPlaybackStart(element) ? "yes" : "no"; | |
| 147 | |
| 148 // We are supposed to scroll the player into view. | |
| 149 element.scrollIntoView(true); | |
| 150 // TODO(liberato): remove once autoplay gesture override experiment
concludes. | |
| 151 internals.triggerAutoplayViewportCheck(element); | |
| 152 // Once these two methods return, changes to the element state due | |
| 153 // to the autoplay experiment should be observable synchronously. | |
| 154 checkElementStatus(element, spec); | |
| 155 } else { | |
| 156 // Record the results immediately. | |
| 157 checkElementStatus(element, spec); | |
| 158 } | |
| 159 }); | |
| 160 | |
| 161 // Set the source, which will eventually lead to canPlayThrough. | |
| 162 element.src = mediaFile; | |
| 163 } | |
| 164 | |
| 165 var experimentTypes = []; // set in start(). | |
| 166 var elementTypes = []; // set in start(). | |
| 167 var autoplayTypes = ["none", "attr", "play()"]; | |
| 168 var mutedTypes = ["no", "yes"]; | |
| 169 var visTypes = ["onscreen", "scroll", "offscreen", "obscured"]; | |
| 170 // mobileTypes must always start with no, since we cannot un-optimize the page. | |
| 171 var mobileTypes = ["no", "yes"]; | |
| 172 var autoplaySettings = ["enabled", "disabled"]; | |
| 173 | |
| 174 function runNextConfig() | |
| 175 { | |
| 176 // Convert configNumber into a spec, and run it. | |
| 177 var exp = configNumber; | |
| 178 | |
| 179 // Convert this experiment number into settings. | |
| 180 var spec = {}; | |
| 181 spec.elementType = elementTypes[exp % elementTypes.length]; | |
| 182 exp = Math.floor(exp / elementTypes.length); | |
| 183 spec.experimentType = experimentTypes[exp % experimentTypes.length]; | |
| 184 exp = Math.floor(exp / experimentTypes.length); | |
| 185 spec.autoplayType = autoplayTypes[exp % autoplayTypes.length]; | |
| 186 exp = Math.floor(exp / autoplayTypes.length); | |
| 187 spec.mutedType = mutedTypes[exp % mutedTypes.length]; | |
| 188 exp = Math.floor(exp / mutedTypes.length); | |
| 189 spec.visType = visTypes[exp % visTypes.length]; | |
| 190 exp = Math.floor(exp / visTypes.length); | |
| 191 spec.settingValue = autoplaySettings[exp % autoplaySettings.length]; | |
| 192 exp = Math.floor(exp / autoplaySettings.length); | |
| 193 // Mobile must always change last, so that all the "no" cases precede | |
| 194 // all the "yes" cases, since we can't switch the doc back to "not | |
| 195 // optimized for mobile". | |
| 196 spec.mobileType = mobileTypes[exp % mobileTypes.length]; | |
| 197 exp = Math.floor(exp / mobileTypes.length); | |
| 198 | |
| 199 spec.experimentNumber = configNumber; | |
| 200 | |
| 201 // Return null if configNumber was larger than the highest experiment. | |
| 202 if (exp > 0) | |
| 203 testRunner.notifyDone(); | |
| 204 | |
| 205 configNumber++; | |
| 206 | |
| 207 // To keep the test fast, skip a few combinations. | |
| 208 var skip = false; | |
| 209 if (!spec.experimentType.includes("-ifmuted") && spec.mutedType != "no") | |
| 210 skip = true; | |
| 211 | |
| 212 // Only allow basic combinations for the mobile case. We just want to | |
| 213 // test video with autoplay, no mute options when testing -ifmobile. | |
| 214 // Similarly, if we're setting the page to be optimied for mobile, then | |
| 215 // require that we're one of those tests. | |
| 216 if ((spec.mobileType == "yes" || spec.experimentType.includes("-ifmobile")) | |
| 217 && (spec.elementType != "video" || spec.autoplayType != "attr" | |
| 218 || spec.mutedType != "no" | |
| 219 || spec.visType != "onscreen" | |
| 220 || (spec.experimentType != "enabled-forvideo" | |
| 221 && spec.experimentType != "enabled-forvideo-ifmobile"))) | |
| 222 skip = true; | |
| 223 | |
| 224 var mismatched =(spec.elementType == "video" | |
| 225 && spec.experimentType.includes("-foraudio")) | |
| 226 || (spec.elementType == "audio" | |
| 227 && spec.experimentType.includes("-forvideo")); | |
| 228 | |
| 229 if (spec.autoplayType == "none" && spec.visType != 'onscreen') | |
| 230 skip = true; | |
| 231 else if (spec.experimentType.includes("-ifmuted") | |
| 232 && spec.visType != "onscreen") | |
| 233 skip = true; | |
| 234 else if (spec.visType == "offscreen" | |
| 235 && spec.autoplayType != "attr") | |
| 236 skip = true; | |
| 237 else if (!spec.experimentType.includes("-ifmuted") | |
| 238 && spec.mutedType == "yes") | |
| 239 skip = true; | |
| 240 else if (spec.elementType == "audio" && spec.mutedType == "yes") | |
| 241 skip = true; | |
| 242 else if (spec.elementType == "audio" && spec.visType != "scroll") | |
| 243 skip = true; | |
| 244 else if (mismatched && spec.visType !="onscreen") | |
| 245 skip = true; | |
| 246 else if (mismatched && spec.autoplayType != "attr") | |
| 247 skip = true; | |
| 248 else if (spec.visType == "obscured" | |
| 249 && !spec.experimentType.includes("-ifpagevisible")) | |
| 250 skip = true; | |
| 251 else if ((spec.visType == "offscreen" || spec.visType == "scroll" | |
| 252 || spec.autoplayType != "attr" || spec.elementType != "video") | |
| 253 && spec.experimentType.includes("-ifpagevisible")) | |
| 254 skip = true; | |
| 255 else if (spec.settingValue == "disabled" | |
| 256 && ((spec.visType != "onscreen") || (spec.autoplayType != "play()"))) | |
| 257 skip = true; | |
| 258 | |
| 259 if (skip) | |
| 260 queueNextExperiment(); | |
| 261 else | |
| 262 runOneConfig(spec); | |
| 263 } | |
| 264 | |
| 265 function start(mediaType, experiments) { | |
| 266 testRunner.waitUntilDone(); | |
| 267 testRunner.dumpAsText(); | |
| 268 elementTypes = [ mediaType ]; | |
| 269 experimentTypes = experiments; | |
| 270 | |
| 271 internals.settings.setMediaPlaybackRequiresUserGesture(true); | |
| 272 runNextConfig(); | |
| 273 } | |
| OLD | NEW |