Source/ThirdParty/libwebrtc:
[WebKit-https.git] / LayoutTests / webrtc / video-stats.html
1 <!doctype html>
2 <html>
3     <head>
4         <meta charset="utf-8">
5         <title>Testing basic video exchange from offerer to receiver</title>
6         <script src="../resources/testharness.js"></script>
7         <script src="../resources/testharnessreport.js"></script>
8     </head>
9     <body>
10         <script src ="routines.js"></script>
11         <script>
12 function getStatsType(connection)
13 {
14     return connection.getStats().then((report) => {
15         var reportTypes = [];
16         report.forEach((statItem) => {
17             if (reportTypes.indexOf(statItem.type) === -1)
18                 reportTypes.push(statItem.type);
19         });
20         return reportTypes.sort();
21     });
22 }
23
24 function checkStatsReportIterator(report)
25 {
26     assert_equals(Object.getOwnPropertyDescriptor(report.__proto__, Symbol.iterator).value, Object.getOwnPropertyDescriptor(report.__proto__, 'entries').value);
27     assert_equals(Object.getOwnPropertyDescriptor(report.__proto__, Symbol.iterator).value.name, "entries");
28     for (let pair of report)
29         assert_equals(pair.length, 2);
30 }
31
32 function getAudioSourceStats(connection)
33 {
34     return connection.getStats().then((report) => {
35         checkStatsReportIterator(report);
36         var stats;
37         report.forEach((statItem) => {
38             if (statItem.type === "media-source" && statItem.kind === "audio") {
39                 stats = statItem;
40             }
41         });
42         return stats;
43     });
44 }
45
46 function getVideoSourceStats(connection)
47 {
48     return connection.getStats().then((report) => {
49         checkStatsReportIterator(report);
50         var stats;
51         report.forEach((statItem) => {
52             if (statItem.type === "media-source" && statItem.kind === "video") {
53                 stats = statItem;
54             }
55         });
56         return stats;
57     });
58 }
59
60 function getInboundRTPStats(connection)
61 {
62     return connection.getStats().then((report) => {
63         checkStatsReportIterator(report);
64         var stats;
65         report.forEach((statItem) => {
66             if (statItem.type === "inbound-rtp") {
67                 stats = statItem;
68             }
69         });
70         return stats;
71     });
72 }
73
74 function getOutboundRTPStats(connection)
75 {
76     return connection.getStats().then((report) => {
77         checkStatsReportIterator(report);
78         var stats;
79         report.forEach((statItem) => {
80             if (statItem.type === "outbound-rtp") {
81                 stats = statItem;
82             }
83         });
84         return stats;
85     });
86 }
87
88 function testTimestampDifference(timeStampDifference, numberOfFrames)
89 {
90     // Let's ensure timestamp is not in microseconds but milliseconds.
91     return timeStampDifference > 100000 * (numberOfFrames / 30.0);
92 }
93
94 function checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, count)
95 {
96     return getInboundRTPStats(secondConnection).then((stats) => {
97         if (stats.framesDecoded > statsSecondConnection.framesDecoded) {
98             if (testTimestampDifference(stats.timestamp - statsSecondConnection.timestamp, stats.framesDecoded - statsSecondConnection.framesDecoded))
99                 return Promise.reject("timestamp and frames increment do not match");
100             assert_not_equals(Object.keys(stats).indexOf("codecId"), -1, "codecId");
101             assert_not_equals(Object.keys(stats).indexOf("trackId"), -1, "trackId");
102             return;
103         }
104         if (++count === 20)
105             return Promise.reject("checking inbound stats frame number increasing timed out");
106         return waitFor(50).then(() => {
107             return checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, count)
108         });
109     });
110 }
111
112 function checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, count)
113 {
114     return getOutboundRTPStats(firstConnection).then((stats) => {
115         if (stats.framesEncoded > statsFirstConnection.framesEncoded) {
116             if (testTimestampDifference(stats.timestamp - statsFirstConnection.timestamp, stats.framesEncoded - statsFirstConnection.framesEncoded))
117                 return Promise.reject("timestamp and frames increment do not match");
118             assert_not_equals(Object.keys(stats).indexOf("codecId"), -1, "codecId");
119             assert_not_equals(Object.keys(stats).indexOf("trackId"), -1, "trackId");
120             return;
121         }
122         if (++count === 20)
123             return Promise.reject("checking outbound stats frame number increasing timed out");
124         return waitFor(50).then(() => {
125             return checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, count)
126         });
127     });
128 }
129
130 var firstConnection, secondConnection;
131 promise_test(async (test) => {
132     if (window.testRunner)
133         testRunner.setUserMediaPermission(true);
134
135     const localStream = await navigator.mediaDevices.getUserMedia({ audio : true, video: true});
136     await new Promise((resolve, reject) => {
137         createConnections((connection) => {
138             firstConnection = connection;
139             firstConnection.addTrack(localStream.getAudioTracks()[0], localStream);
140             firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
141         }, (connection) => {
142             secondConnection = connection;
143             secondConnection.addTrack(localStream.getAudioTracks()[0], localStream);
144             secondConnection.addTrack(localStream.getVideoTracks()[0], localStream);
145             secondConnection.ontrack = (trackEvent) => {
146                 resolve();
147             };
148         });
149         setTimeout(() => reject("Test timed out"), 5000);
150     });
151
152     let stats = await getOutboundRTPStats(firstConnection);
153     assert_true(!!stats, "outbound-rtp stats should not be null");
154     assert_true(Number.isInteger(stats.framesEncoded), "framesEncoded should be an integer");
155     assert_true(Number.isInteger(stats.qpSum), "outbound qpSum should be an integer");
156     assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
157     statsFirstConnection = stats;
158
159     stats = await getInboundRTPStats(secondConnection);
160     assert_true(!!stats, "inbound-rtp stats should not be null");
161     assert_true(Number.isInteger(stats.framesDecoded), "framesDecoded should be an integer");
162     assert_true(Number.isInteger(stats.qpSum), "inbound qpSum should be an integer");
163     assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
164     statsSecondConnection = stats;
165
166     await checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, 0);
167     await checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, 0);
168
169     let types = await getStatsType(firstConnection);
170     assert_array_equals(types, ["candidate-pair", "certificate", "codec", "inbound-rtp", "local-candidate", "media-source", "outbound-rtp", "peer-connection", "remote-candidate", "track", "transport"]);
171
172     types = await getStatsType(secondConnection);
173     assert_array_equals(types, ["candidate-pair", "certificate", "codec", "inbound-rtp", "local-candidate", "media-source", "outbound-rtp", "peer-connection", "remote-candidate", "track", "transport"]);
174
175      const audioSourceStats = await getAudioSourceStats(firstConnection);
176      assert_true(!!audioSourceStats, "audio source presence");
177
178      const videoSourceStats = await getVideoSourceStats(firstConnection);
179      assert_true(!!videoSourceStats, "video source presence");
180 }, "Basic video stats");
181
182 promise_test(async (test) => {
183     const report = await firstConnection.getSenders()[0].getStats();
184     checkStatsReportIterator(report);
185     var instats, outstats;
186     report.forEach((statItem) => {
187         if (statItem.type === "outbound-rtp")
188             outstats = statItem;
189         else if (statItem.type === "inbound-rtp")
190             instats = statItem;
191     });
192     assert_true(!!outstats);
193     assert_false(!!instats);
194 }, "Sender stats");
195
196 promise_test(async (test) => {
197     const report = await secondConnection.getReceivers()[0].getStats();
198     checkStatsReportIterator(report);
199     var instats, outstats;
200     report.forEach((statItem) => {
201         if (statItem.type === "outbound-rtp")
202             outstats = statItem;
203         else if (statItem.type === "inbound-rtp")
204             instats = statItem;
205     });
206     assert_false(!!outstats);
207     assert_true(!!instats);
208 }, "Receiver stats");
209
210 promise_test(async (test) => {
211     let instats1, instats2;
212
213     let report1 = await secondConnection.getReceivers()[0].getStats();
214     report1.forEach((statItem) => {
215         if (statItem.type === "inbound-rtp")
216             instats1 = statItem;
217     });
218     waitFor(50);
219     let report2 = await secondConnection.getReceivers()[0].getStats();
220     report2.forEach((statItem) => {
221         if (statItem.type === "inbound-rtp")
222             instats2 = statItem;
223     });
224     assert_equals(instats1.ssrc, instats2.ssrc);
225 }, "Check ssrc is not changing in inbound rtp stats");
226
227 promise_test(async (test) => {
228     const pc = new RTCPeerConnection();
229     pc.close();
230     return pc.getStats();
231 }, "Stats after pc close");
232         </script>
233     </body>
234 </html>