Live video on the AT Protocol
at eli/optional-convergence 125 lines 3.6 kB view raw
1import { v7 as uuidv7 } from "uuid"; 2import { makeWindow } from "../window"; 3import { E2ETest, TestEnv } from "./test-env"; 4import { delay, PlayerReport } from "./util"; 5 6const PLAYING_SUCCESS = 0.5; 7 8export const playbackTest: E2ETest = { 9 setup: async (testEnv: TestEnv) => { 10 return { 11 ...testEnv, 12 env: { 13 ...testEnv.env, 14 SP_TEST_STREAM: "true", 15 }, 16 }; 17 }, 18 test: async (testEnv: TestEnv): Promise<string | null> => { 19 const mainWindow = await makeWindow(); 20 21 const testId = uuidv7(); 22 const definitions = [ 23 // { 24 // name: "hls", 25 // forceProtocol: "hls", 26 // }, 27 { 28 name: "progressive-mp4", 29 forceProtocol: "progressive-mp4", 30 }, 31 { 32 name: "progressive-webm", 33 forceProtocol: "progressive-webm", 34 }, 35 { 36 name: "webrtc", 37 forceProtocol: "webrtc", 38 }, 39 ]; 40 const tests = definitions.map((x) => ({ 41 name: x.name, 42 playerId: `${testId}-${x.name}`, 43 src: "self-test", 44 showControls: true, 45 telemetry: true, 46 forceProtocol: x.forceProtocol, 47 })); 48 const enc = encodeURIComponent(JSON.stringify(tests)); 49 50 const load = `${testEnv.addr}/multi/${enc}`; 51 52 console.log(`opening ${load}`); 53 mainWindow.loadURL(load); 54 55 let foundThumbnail = false; 56 const interval = setInterval(async () => { 57 const thumb = `${testEnv.addr}/api/playback/self-test/stream.jpg`; 58 console.log(`fetching thumbnail at ${thumb}`); 59 const res = await fetch(thumb); 60 if (res.status === 404) { 61 console.log("no thumbnail found"); 62 return; 63 } 64 if (res.status !== 200) { 65 console.log( 66 `unexpected http status ${res.status}, failing thumbnail test`, 67 ); 68 clearInterval(interval); 69 return; 70 } 71 const blob = await res.arrayBuffer(); 72 if (blob.byteLength < 1) { 73 console.log("thumbnail was empty :("); 74 return; 75 } 76 console.log("found thumbnail!"); 77 foundThumbnail = true; 78 clearInterval(interval); 79 }, 1000); 80 81 await delay(testEnv.testDuration); 82 clearInterval(interval); 83 const reports = await Promise.all( 84 tests.map(async (t) => { 85 const res = await fetch( 86 `${testEnv.internalAddr}/player-report/${t.playerId}`, 87 ); 88 const data = (await res.json()) as PlayerReport; 89 return { ...t, data: data.whatHappened, retries: data.retries }; 90 }), 91 ); 92 const failures = []; 93 if (!foundThumbnail) { 94 console.log("never found a thumbnail, failing test"); 95 failures.push("never found a thumbnail"); 96 } 97 const percentages = reports.map((report) => { 98 if (typeof report.retries === "number" && report.retries > 1) { 99 console.log(`${report.name} had ${report.retries} retries`); 100 // we only care about webrtc failures right now 101 if (report.name === "webrtc") { 102 failures.push("webrtc had retries"); 103 } 104 } 105 let total = 0; 106 for (const [state, ms] of Object.entries(report.data)) { 107 total += ms; 108 } 109 const pcts: { [k: string]: number } = { playing: 0 }; 110 for (const [state, ms] of Object.entries(report.data)) { 111 pcts[state] = ms / total; 112 } 113 if (pcts.playing < PLAYING_SUCCESS) { 114 failures.push("playing was less than 50%"); 115 } 116 return { ...report, pcts }; 117 }); 118 console.log(JSON.stringify(percentages, null, 2)); 119 await mainWindow.close(); 120 if (failures.length > 0) { 121 return failures.join(", "); 122 } 123 return null; 124 }, 125};