Skip to content

Commit 5a82cbb

Browse files
committed
Update session test to handle additional latency stats
1 parent 80e2590 commit 5a82cbb

File tree

2 files changed

+68
-53
lines changed

2 files changed

+68
-53
lines changed

Frontend/ui-library/src/UI/SessionTest.ts

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,11 @@
22

33
import {
44
AggregatedStats,
5-
InboundVideoStats,
6-
InboundAudioStats,
5+
LatencyInfo,
76
Logger,
8-
SettingNumber,
9-
CandidatePairStats,
10-
DataChannelStats,
11-
OutboundRTPStats,
12-
CandidateStat,
13-
RemoteOutboundRTPStats
7+
SettingNumber
148
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5';
15-
import { StatsSections } from './UIConfigurationTypes';
169
import { SettingUINumber } from '../Config/SettingUINumber';
17-
import { InboundRTPStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5/dist/types/PeerConnectionController/InboundRTPStats';
18-
19-
type InboundRTPStatsKeys = Exclude<keyof typeof InboundRTPStats, 'prototype'>;
20-
type InboundRTPStatsIds = (typeof InboundRTPStats)[InboundRTPStatsKeys];
21-
22-
type InboundVideoStatsKeys = Exclude<keyof typeof InboundVideoStats, 'prototype'>;
23-
type InboundVideoStatsIds = (typeof InboundVideoStats)[InboundVideoStatsKeys];
24-
25-
type InboundAudioStatsKeys = Exclude<keyof typeof InboundAudioStats, 'prototype'>;
26-
type InboundAudioStatsIds = (typeof InboundAudioStats)[InboundAudioStatsKeys];
27-
28-
type CandidatePairStatsKeys = Exclude<keyof typeof CandidatePairStats, 'prototype'>;
29-
type CandidatePairStatsIds = (typeof CandidatePairStats)[CandidatePairStatsKeys];
30-
31-
type DataChannelStatsKeys = Exclude<keyof typeof DataChannelStats, 'prototype'>;
32-
type DataChannelStatsIds = (typeof DataChannelStats)[DataChannelStatsKeys];
33-
34-
type CandidateStatKeys = Exclude<keyof typeof CandidateStat, 'prototype'>;
35-
type CandidateStatKeysIds = (typeof CandidateStat)[CandidateStatKeys];
36-
37-
type OutboundRTPStatsKeys = Exclude<keyof typeof OutboundRTPStats, 'prototype'>;
38-
type OutboundRTPStatsIds = (typeof OutboundRTPStats)[OutboundRTPStatsKeys];
39-
40-
type RemoteOutboundRTPStatsKeys = Exclude<keyof typeof RemoteOutboundRTPStats, 'prototype'>;
41-
type RemoteOutboundRTPStatsIds = (typeof RemoteOutboundRTPStats)[RemoteOutboundRTPStatsKeys];
42-
43-
type StatsIds =
44-
| InboundRTPStatsIds
45-
| InboundVideoStatsIds
46-
| InboundAudioStatsIds
47-
| CandidatePairStatsIds
48-
| DataChannelStatsIds
49-
| OutboundRTPStatsIds
50-
| CandidateStatKeysIds
51-
| RemoteOutboundRTPStatsIds;
52-
53-
type AggregatedStatsKeys = Exclude<keyof typeof AggregatedStats, 'prototype'>;
54-
type AggregatedStatsIds = (typeof AggregatedStats)[AggregatedStatsKeys];
55-
56-
type AllIds = AggregatedStatsIds | StatsIds;
5710
/**
5811
* Session test UI elements and results handling.
5912
*/
@@ -65,6 +18,7 @@ export class SessionTest {
6518
isCollectingStats: boolean;
6619

6720
records: AggregatedStats[];
21+
latencyRecords: LatencyInfo[];
6822

6923
constructor() {
7024
this.isCollectingStats = false;
@@ -122,6 +76,7 @@ export class SessionTest {
12276

12377
this._latencyTestButton.onclick = () => {
12478
this.records = [];
79+
this.latencyRecords = [];
12580
this.isCollectingStats = true;
12681
Logger.Warning(`Starting session test. Duration: [${this._testTimeFrameSetting.number}]`);
12782
setTimeout(() => {
@@ -141,15 +96,29 @@ export class SessionTest {
14196
this.records.push(statsCopy);
14297
}
14398

99+
public handleLatencyInfo(latencyInfo: LatencyInfo) {
100+
if (!this.isCollectingStats) {
101+
return;
102+
}
103+
104+
const latencyInfoCopy = structuredClone(latencyInfo);
105+
this.latencyRecords.push(latencyInfoCopy);
106+
}
107+
144108
private onCollectingFinished() {
145109
this.isCollectingStats = false;
146110
Logger.Warning(`Finished session test`);
147111

112+
this.generateStatsCsv();
113+
this.generateLatencyCsv();
114+
}
115+
116+
private generateStatsCsv() {
148117
const csvHeader: string[] = [];
149118

150119
this.records.forEach((record) => {
151120
for (const i in record) {
152-
const obj: {} = record[i as AggregatedStatsIds];
121+
const obj: {} = record[i as never];
153122

154123
if (Array.isArray(obj)) {
155124
for (const j in obj) {
@@ -180,10 +149,54 @@ export class SessionTest {
180149
});
181150

182151
let csvBody = '';
183-
this.records.forEach((record) =>{
152+
this.records.forEach((record) => {
153+
csvHeader.forEach((field) => {
154+
try {
155+
csvBody += `"${field.split('.').reduce((o, k) => o[k as never], record)}",`;
156+
} catch (_) {
157+
csvBody += `"",`;
158+
}
159+
});
160+
csvBody += `\n`;
161+
});
162+
163+
const file = new Blob([`${csvHeader.join(',')}\n${csvBody}`], { type: 'text/plain' });
164+
const a = document.createElement('a');
165+
const url = URL.createObjectURL(file);
166+
a.href = url;
167+
a.download = 'stats.csv';
168+
document.body.appendChild(a);
169+
a.click();
170+
setTimeout(function () {
171+
document.body.removeChild(a);
172+
window.URL.revokeObjectURL(url);
173+
}, 0);
174+
}
175+
176+
private generateLatencyCsv() {
177+
const csvHeader: string[] = [];
178+
179+
this.latencyRecords.forEach((record) => {
180+
for (const i in record) {
181+
const obj = record[i as never];
182+
183+
if (typeof obj === 'object') {
184+
for (const j in obj as object) {
185+
if (csvHeader.indexOf(`${i}.${j}`) === -1) {
186+
csvHeader.push(`${i}.${j}`);
187+
}
188+
}
189+
} else if (csvHeader.indexOf(`${i}`) === -1) {
190+
csvHeader.push(`${i}`);
191+
}
192+
}
193+
});
194+
195+
let csvBody = '';
196+
this.latencyRecords.forEach((record) => {
184197
csvHeader.forEach((field) => {
185198
try {
186-
csvBody += `"${field.split('.').reduce((o, k) => o[k as AllIds], record)}",`;
199+
csvBody += `"${field.split('.').reduce((o, k) => o[k as never], record)}",`;
187200
} catch (_) {
188201
csvBody += `"",`;
189202
}
@@ -195,7 +208,7 @@ export class SessionTest {
195208
const a = document.createElement('a');
196209
const url = URL.createObjectURL(file);
197210
a.href = url;
198-
a.download = 'test_results.csv';
211+
a.download = 'latency.csv';
199212
document.body.appendChild(a);
200213
a.click();
201214
setTimeout(function () {

Frontend/ui-library/src/UI/StatsPanel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ export class StatsPanel {
389389
}
390390

391391
public handleLatencyInfo(latencyInfo: LatencyInfo) {
392+
this.sessionTest.handleLatencyInfo(latencyInfo);
393+
392394
if (latencyInfo.frameTiming !== undefined) {
393395
// Encoder latency
394396
if (latencyInfo.frameTiming.encoderLatencyMs !== undefined) {

0 commit comments

Comments
 (0)