22
33import {
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' ;
169import { 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 ( ) {
0 commit comments