audiocontext-playoutstats.html (5741B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Testing AudioContext.playoutStats attribute</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 </head> 8 9 <body> 10 <script> 11 function should_be_in_range(value, min, max) { 12 assert_greater_than_equal(value, min); 13 assert_less_than_equal(value, max); 14 } 15 16 promise_test(async (t) => { 17 let context = new AudioContext(); 18 assert_not_equals(context.playoutStats, null); 19 20 // Initially, the stats should all be 0. 21 let stats = context.playoutStats; 22 assert_equals(stats.totalFramesDuration, 0); 23 assert_equals(stats.fallbackFramesDuration, 0); 24 assert_equals(stats.fallbackFramesEvents, 0); 25 assert_equals(stats.minimumLatency, 0); 26 assert_equals(stats.maximumLatency, 0); 27 assert_equals(stats.averageLatency, 0); 28 29 // Asynchronously wait for 1.5 seconds. We will then check that the 30 // stats reflect that the context has been playing for at least 0.9 31 // seconds. The 0.1 second margin is needed because the stats are 32 // updated once per second, and the context is not guaranteed to have 33 // been playing for exactly 1 second by the time they are updated. 34 // The extra 0.5 seconds of margin after the 1 second mark is to avoid 35 // flakiness. 36 // Note that awaiting moves us to a new task in the execution cycle, 37 // which allows the stats to change. 38 await new Promise((r) => step_timeout(r, 1500)); 39 assert_greater_than(stats.totalFramesDuration, 900); 40 should_be_in_range( 41 stats.fallbackFramesDuration, 42 0, 43 stats.totalFramesDuration 44 ); 45 assert_greater_than_equal(stats.fallbackFramesEvents, 0); 46 assert_greater_than_equal(stats.minimumLatency, 0); 47 assert_greater_than_equal(stats.maximumLatency, 0); 48 should_be_in_range( 49 stats.averageLatency, 50 stats.minimumLatency, 51 stats.maximumLatency 52 ); 53 }, "Test that the stats increase during playout"); 54 55 promise_test(async (t) => { 56 let context = new AudioContext(); 57 58 // Wait a while so that we get stats that aren't all zeroes. 59 await new Promise((r) => step_timeout(r, 1500)); 60 let stats = context.playoutStats; 61 assert_greater_than(stats.totalFramesDuration, 1000); 62 63 // Check that the stats from the toJSON object match the PlayoutStats 64 // object. 65 let json = stats.toJSON(); 66 assert_equals(json.totalFramesDuration, stats.totalFramesDuration); 67 assert_equals( 68 json.fallbackFramesDuration, 69 stats.fallbackFramesDuration 70 ); 71 assert_equals(json.fallbackFramesEvents, stats.fallbackFramesEvents); 72 assert_equals(json.minimumLatency, stats.minimumLatency); 73 assert_equals(json.maximumLatency, stats.maximumLatency); 74 assert_equals(json.averageLatency, stats.averageLatency); 75 }, "Test that toJSON reflects the current stats"); 76 77 promise_test(async (t) => { 78 let context = new AudioContext(); 79 80 // Wait a while so that we get stats that aren't all zeroes. 81 await new Promise((r) => step_timeout(r, 1500)); 82 let stats = context.playoutStats; 83 assert_greater_than(stats.totalFramesDuration, 1000); 84 85 // Average latency should be between minimum and maximum. 86 let beforeReset = stats.toJSON(); 87 should_be_in_range( 88 beforeReset.averageLatency, 89 beforeReset.minimumLatency, 90 beforeReset.maximumLatency 91 ); 92 93 // After a reset, the minimum, maximum and average latencies should be 94 // the same. 95 stats.resetLatency(); 96 let afterReset = stats.toJSON(); 97 assert_equals(afterReset.minimumLatency, afterReset.averageLatency); 98 assert_equals(afterReset.maximumLatency, afterReset.averageLatency); 99 }, "Test PlayoutStats.resetLatency()"); 100 101 promise_test(async (t) => { 102 // Tests that the API adheres to run to completion semantics, as 103 // defined here: https://w3ctag.github.io/design-principles/#js-rtc 104 let context = new AudioContext(); 105 106 // Wait a while so that we get stats that aren't all zeroes. 107 await new Promise((r) => step_timeout(r, 1500)); 108 let stats = context.playoutStats; 109 assert_greater_than(stats.totalFramesDuration, 1000); 110 let beforeWait = stats.toJSON(); 111 112 // Synchronously wait 1500 ms. 113 const start = performance.now(); 114 while (performance.now() - start < 1500); 115 116 // We are still in the same execution cycle, so the stats shouldn't 117 // have changed. 118 assert_equals( 119 stats.totalFramesDuration, 120 beforeWait.totalFramesDuration 121 ); 122 assert_equals( 123 stats.fallbackFramesDuration, 124 beforeWait.fallbackFramesDuration 125 ); 126 assert_equals( 127 stats.fallbackFramesEvents, 128 beforeWait.fallbackFramesEvents 129 ); 130 assert_equals(stats.minimumLatency, beforeWait.minimumLatency); 131 assert_equals(stats.maximumLatency, beforeWait.maximumLatency); 132 assert_equals(stats.averageLatency, beforeWait.averageLatency); 133 134 // Move to the next execution cycle. Since it was 500 ms since the 135 // stats were last updated, they have now increased. 136 await Promise.resolve(); 137 assert_greater_than( 138 stats.totalFramesDuration, 139 beforeWait.totalFramesDuration 140 ); 141 }, "Test that stats are unchanged within the same execution cycle."); 142 </script> 143 </body> 144 </html>