@vpalmisano/webrtcperf 4.6.2 → 4.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mcpRunner = mcpRunner;
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const throttler_1 = require("@vpalmisano/throttler");
7
+ const zod_1 = require("zod");
8
+ const config_1 = require("./config");
9
+ const session_1 = require("./session");
10
+ const stats_1 = require("./stats");
11
+ const media_1 = require("./media");
12
+ const utils_1 = require("./utils");
13
+ const log = (0, utils_1.logger)('webrtcperf:mcp');
14
+ const mcpServer = new mcp_js_1.McpServer({
15
+ name: 'webrtcperf',
16
+ version: '1.0.0',
17
+ });
18
+ let stats;
19
+ let statsReady;
20
+ async function getStats() {
21
+ if (!stats) {
22
+ const [defaultConfig] = await (0, config_1.loadConfig)(undefined, {
23
+ showStats: false,
24
+ });
25
+ if (!defaultConfig.startTimestamp) {
26
+ defaultConfig.startTimestamp = Date.now();
27
+ }
28
+ stats = new stats_1.Stats(defaultConfig);
29
+ stats.on('stats', () => {
30
+ mcpServer.server.sendResourceUpdated({ uri: 'webrtcperf://stats' });
31
+ });
32
+ statsReady = stats.start();
33
+ }
34
+ await statsReady;
35
+ return stats;
36
+ }
37
+ async function startSessionHandler(args) {
38
+ const { config } = args;
39
+ log.debug('startSessionHandler', config);
40
+ const stats = await getStats();
41
+ const configs = await (0, config_1.loadConfig)(undefined, config);
42
+ const sessionConfig = configs[0];
43
+ const tabsPerSession = sessionConfig.tabsPerSession ?? 1;
44
+ const id = stats.consumeSessionId(tabsPerSession);
45
+ const throttleIndex = (0, throttler_1.getSessionThrottleIndex)(id);
46
+ const spawnRate = sessionConfig.spawnRate ?? 1;
47
+ const spawnPeriod = 1000 / spawnRate;
48
+ const throttleConfig = sessionConfig.throttleConfig;
49
+ if (throttleConfig) {
50
+ await (0, throttler_1.startThrottle)(throttleConfig);
51
+ }
52
+ const mediaPaths = [];
53
+ const videoPath = sessionConfig.videoPath;
54
+ if (videoPath) {
55
+ for (const vp of videoPath.split(',')) {
56
+ const ret = await (0, media_1.prepareFakeMedia)({ ...sessionConfig, videoPath: vp });
57
+ mediaPaths.push(ret);
58
+ }
59
+ }
60
+ const mediaPath = mediaPaths.length ? mediaPaths[id % mediaPaths.length] : undefined;
61
+ if (sessionConfig.url.startsWith('https://meet.google.com')) {
62
+ if (!sessionConfig.scriptPath) {
63
+ sessionConfig.scriptPath =
64
+ 'https://raw.githubusercontent.com/vpalmisano/webrtcperf/refs/heads/devel/examples/google-meet.js';
65
+ }
66
+ if (!sessionConfig.scriptParams) {
67
+ sessionConfig.scriptParams = '{"enableMic": true, "enableCam": true}';
68
+ }
69
+ if (!sessionConfig.debuggingPort) {
70
+ sessionConfig.debuggingPort = 9000;
71
+ }
72
+ }
73
+ else if (sessionConfig.url.startsWith('https://meet.livekit.io')) {
74
+ if (!sessionConfig.scriptPath) {
75
+ sessionConfig.scriptPath =
76
+ 'https://raw.githubusercontent.com/vpalmisano/webrtcperf/refs/heads/devel/examples/livekit.js';
77
+ }
78
+ }
79
+ const session = new session_1.Session({
80
+ ...sessionConfig,
81
+ throttleIndex,
82
+ spawnPeriod,
83
+ mediaPath,
84
+ id,
85
+ });
86
+ session.once('stop', () => {
87
+ setTimeout(() => startSessionHandler({ config }).catch(() => { }), spawnPeriod);
88
+ });
89
+ stats.addSession(session);
90
+ try {
91
+ await session.start();
92
+ }
93
+ catch (err) {
94
+ stats.removeSession(session.id);
95
+ throw err;
96
+ }
97
+ if (sessionConfig.runDuration) {
98
+ setTimeout(() => {
99
+ session.removeAllListeners();
100
+ session.stop();
101
+ stats.removeSession(session.id);
102
+ }, sessionConfig.runDuration * 1000);
103
+ }
104
+ return {
105
+ content: [
106
+ {
107
+ type: 'text',
108
+ text: JSON.stringify({ message: 'Session created', id }, null, 2),
109
+ },
110
+ ],
111
+ };
112
+ }
113
+ async function stopSessionHandler(args) {
114
+ const { id } = args;
115
+ log.debug('stopSessionHandler', id);
116
+ const s = await getStats();
117
+ const session = s.sessions.get(id);
118
+ if (!session) {
119
+ return {
120
+ content: [
121
+ {
122
+ type: 'text',
123
+ text: JSON.stringify({ message: 'Session not found', id }, null, 2),
124
+ },
125
+ ],
126
+ };
127
+ }
128
+ session.removeAllListeners();
129
+ s.removeSession(id);
130
+ await session.stop();
131
+ return {
132
+ content: [
133
+ {
134
+ type: 'text',
135
+ text: JSON.stringify({ message: 'Session deleted', id }),
136
+ },
137
+ ],
138
+ };
139
+ }
140
+ async function getSessionsHandler() {
141
+ const s = await getStats();
142
+ const sessions = Array.from(s.sessions.entries()).map(([id, session]) => ({
143
+ id,
144
+ stats: session.stats,
145
+ }));
146
+ log.debug('getSessionsHandler', sessions);
147
+ return {
148
+ content: [
149
+ {
150
+ type: 'text',
151
+ text: JSON.stringify({ sessions, count: sessions.length }),
152
+ },
153
+ ],
154
+ };
155
+ }
156
+ async function resetStatsHandler() {
157
+ const s = await getStats();
158
+ log.debug('resetStatsHandler');
159
+ s.resetStats();
160
+ await mcpServer.server.sendResourceUpdated({ uri: 'webrtcperf://stats' });
161
+ return {
162
+ content: [
163
+ {
164
+ type: 'text',
165
+ text: JSON.stringify({ message: 'Stats reset' }),
166
+ },
167
+ ],
168
+ };
169
+ }
170
+ async function getStatsReadHandler(uri) {
171
+ const stats = await getStats();
172
+ log.debug('getStatsReadHandler', uri.href);
173
+ return {
174
+ contents: [
175
+ {
176
+ uri: uri.href,
177
+ mimeType: 'application/json',
178
+ text: JSON.stringify(stats.collectedStats),
179
+ },
180
+ ],
181
+ };
182
+ }
183
+ mcpServer.registerTool('start_session', {
184
+ description: 'Start a new webrtcperf session in-process. Config is the session config object (url, tabsPerSession, throttleConfig, etc.). Returns the created session id.',
185
+ inputSchema: { config: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()) },
186
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
187
+ },
188
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
189
+ startSessionHandler);
190
+ mcpServer.registerTool('stop_session', {
191
+ description: 'Stop a webrtcperf session by id.',
192
+ inputSchema: { id: zod_1.z.number().int().nonnegative() },
193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
+ },
195
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
196
+ stopSessionHandler);
197
+ mcpServer.registerTool('get_sessions', {
198
+ description: 'List current webrtcperf sessions (id and stats for each running session).',
199
+ }, getSessionsHandler);
200
+ mcpServer.registerTool('reset_stats', {
201
+ description: 'Reset the collected webrtcperf stats.',
202
+ }, resetStatsHandler);
203
+ mcpServer.registerResource('stats', 'webrtcperf://stats', { description: 'Get the current webrtcperf stats.' }, getStatsReadHandler);
204
+ async function mcpRunner() {
205
+ log.debug('mcpRunner');
206
+ const transport = new stdio_js_1.StdioServerTransport();
207
+ await mcpServer.connect(transport);
208
+ }
209
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { getSessionThrottleIndex, startThrottle } from '@vpalmisano/throttler'\nimport { z } from 'zod'\n\nimport { loadConfig } from './config'\nimport type { Config } from './config'\nimport { Session } from './session'\nimport { Stats } from './stats'\nimport { MediaPath, prepareFakeMedia } from './media'\nimport { logger } from './utils'\n\nconst log = logger('webrtcperf:mcp')\n\nconst mcpServer = new McpServer({\n name: 'webrtcperf',\n version: '1.0.0',\n})\n\nlet stats: Stats\nlet statsReady: Promise<void>\n\nasync function getStats(): Promise<Stats> {\n if (!stats) {\n const [defaultConfig] = await loadConfig(undefined, {\n showStats: false,\n })\n if (!defaultConfig.startTimestamp) {\n defaultConfig.startTimestamp = Date.now()\n }\n stats = new Stats(defaultConfig)\n stats.on('stats', () => {\n mcpServer.server.sendResourceUpdated({ uri: 'webrtcperf://stats' })\n })\n statsReady = stats.start()\n }\n await statsReady\n return stats\n}\n\nasync function startSessionHandler(args: {\n config: Record<string, unknown>\n}): Promise<{ content: Array<{ type: 'text'; text: string }> }> {\n const { config } = args\n log.debug('startSessionHandler', config)\n const stats = await getStats()\n const configs = await loadConfig(undefined, config as Partial<Config>)\n const sessionConfig = configs[0]\n const tabsPerSession = sessionConfig.tabsPerSession ?? 1\n const id = stats.consumeSessionId(tabsPerSession)\n const throttleIndex = getSessionThrottleIndex(id)\n const spawnRate = (sessionConfig as Config & { spawnRate?: number }).spawnRate ?? 1\n const spawnPeriod = 1000 / spawnRate\n const throttleConfig = (sessionConfig as Config & { throttleConfig?: string }).throttleConfig\n if (throttleConfig) {\n await startThrottle(throttleConfig)\n }\n const mediaPaths: MediaPath[] = []\n const videoPath = sessionConfig.videoPath\n if (videoPath) {\n for (const vp of videoPath.split(',')) {\n const ret = await prepareFakeMedia({ ...sessionConfig, videoPath: vp })\n mediaPaths.push(ret)\n }\n }\n const mediaPath = mediaPaths.length ? mediaPaths[id % mediaPaths.length] : undefined\n\n if (sessionConfig.url.startsWith('https://meet.google.com')) {\n if (!sessionConfig.scriptPath) {\n sessionConfig.scriptPath =\n 'https://raw.githubusercontent.com/vpalmisano/webrtcperf/refs/heads/devel/examples/google-meet.js'\n }\n if (!sessionConfig.scriptParams) {\n sessionConfig.scriptParams = '{\"enableMic\": true, \"enableCam\": true}'\n }\n if (!sessionConfig.debuggingPort) {\n sessionConfig.debuggingPort = 9000\n }\n } else if (sessionConfig.url.startsWith('https://meet.livekit.io')) {\n if (!sessionConfig.scriptPath) {\n sessionConfig.scriptPath =\n 'https://raw.githubusercontent.com/vpalmisano/webrtcperf/refs/heads/devel/examples/livekit.js'\n }\n }\n\n const session = new Session({\n ...sessionConfig,\n throttleIndex,\n spawnPeriod,\n mediaPath,\n id,\n })\n session.once('stop', () => {\n setTimeout(() => startSessionHandler({ config }).catch(() => {}), spawnPeriod)\n })\n stats.addSession(session)\n try {\n await session.start()\n } catch (err) {\n stats.removeSession(session.id)\n throw err\n }\n if (sessionConfig.runDuration) {\n setTimeout(() => {\n session.removeAllListeners()\n session.stop()\n stats.removeSession(session.id)\n }, sessionConfig.runDuration * 1000)\n }\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ message: 'Session created', id }, null, 2),\n },\n ],\n }\n}\n\nasync function stopSessionHandler(args: { id: number }): Promise<{\n content: Array<{ type: 'text'; text: string }>\n}> {\n const { id } = args\n log.debug('stopSessionHandler', id)\n const s = await getStats()\n const session = s.sessions.get(id)\n if (!session) {\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ message: 'Session not found', id }, null, 2),\n },\n ],\n }\n }\n session.removeAllListeners()\n s.removeSession(id)\n await session.stop()\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ message: 'Session deleted', id }),\n },\n ],\n }\n}\n\nasync function getSessionsHandler(): Promise<{ content: Array<{ type: 'text'; text: string }> }> {\n const s = await getStats()\n const sessions = Array.from(s.sessions.entries()).map(([id, session]) => ({\n id,\n stats: session.stats,\n }))\n log.debug('getSessionsHandler', sessions)\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ sessions, count: sessions.length }),\n },\n ],\n }\n}\n\nasync function resetStatsHandler(): Promise<{ content: Array<{ type: 'text'; text: string }> }> {\n const s = await getStats()\n log.debug('resetStatsHandler')\n s.resetStats()\n await mcpServer.server.sendResourceUpdated({ uri: 'webrtcperf://stats' })\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ message: 'Stats reset' }),\n },\n ],\n }\n}\n\nasync function getStatsReadHandler(uri: URL): Promise<{\n contents: Array<{ uri: string; mimeType: string; text: string }>\n}> {\n const stats = await getStats()\n log.debug('getStatsReadHandler', uri.href)\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify(stats.collectedStats),\n },\n ],\n }\n}\n\nmcpServer.registerTool(\n 'start_session',\n {\n description:\n 'Start a new webrtcperf session in-process. Config is the session config object (url, tabsPerSession, throttleConfig, etc.). Returns the created session id.',\n inputSchema: { config: z.record(z.string(), z.unknown()) },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n startSessionHandler as any,\n)\n\nmcpServer.registerTool(\n 'stop_session',\n {\n description: 'Stop a webrtcperf session by id.',\n inputSchema: { id: z.number().int().nonnegative() },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stopSessionHandler as any,\n)\n\nmcpServer.registerTool(\n 'get_sessions',\n {\n description: 'List current webrtcperf sessions (id and stats for each running session).',\n },\n getSessionsHandler,\n)\n\nmcpServer.registerTool(\n 'reset_stats',\n {\n description: 'Reset the collected webrtcperf stats.',\n },\n resetStatsHandler,\n)\n\nmcpServer.registerResource(\n 'stats',\n 'webrtcperf://stats',\n { description: 'Get the current webrtcperf stats.' },\n getStatsReadHandler,\n)\n\nexport async function mcpRunner(): Promise<void> {\n log.debug('mcpRunner')\n const transport = new StdioServerTransport()\n await mcpServer.connect(transport)\n}\n"]}
@@ -2,7 +2,6 @@ export type MediaPath = {
2
2
  video: string;
3
3
  audio: string;
4
4
  mp4: string;
5
- m4a: string;
6
5
  };
7
6
  /**
8
7
  * Converts the video file into raw audio and video files.
@@ -47,19 +47,16 @@ async function prepareFakeMedia({ videoPath, videoWidth, videoHeight, videoFrame
47
47
  const destMp4Path = useFakeMedia
48
48
  ? ''
49
49
  : `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.mp4`;
50
- const destM4aPath = useFakeMedia ? '' : `${videoCachePath}/${name}.m4a`;
51
50
  if (!(0, fs_1.existsSync)(destVideoPath) ||
52
51
  !(0, fs_1.existsSync)(destAudioPath) ||
53
52
  (destMp4Path && !(0, fs_1.existsSync)(destMp4Path)) ||
54
- (destM4aPath && !(0, fs_1.existsSync)(destM4aPath)) ||
55
53
  !videoCacheRaw) {
56
- log.info(`Converting ${videoPath} to ${destVideoPath}, ${destAudioPath}${destMp4Path ? `, ${destMp4Path}` : ''}${destM4aPath ? `, ${destM4aPath}` : ''}`);
54
+ log.info(`Converting ${videoPath} to ${destVideoPath}, ${destAudioPath}${destMp4Path ? `, ${destMp4Path}` : ''}`);
57
55
  const destVideoPathTmp = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.${videoFormat}`;
58
56
  const destAudioPathTmp = `${videoCachePath}/${name}.tmp.wav`;
59
57
  const destMp4PathTmp = useFakeMedia
60
58
  ? ''
61
59
  : `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.mp4`;
62
- const destM4aPathTmp = useFakeMedia ? '' : `${videoCachePath}/${name}.tmp.m4a`;
63
60
  try {
64
61
  let source = `-i "${videoPath}"`;
65
62
  const videoMap = `-map 0:v`;
@@ -81,17 +78,14 @@ async function prepareFakeMedia({ videoPath, videoWidth, videoHeight, videoFrame
81
78
  ` ${videoMap} ${destVideoPathTmp}` +
82
79
  ` ${audioMap} -ar 48000 ${destAudioPathTmp}` +
83
80
  (destMp4PathTmp
84
- ? ` ${videoMap} -c:v libx264 -crf 10 -f mp4 -movflags faststart ${destMp4PathTmp}` +
85
- ` ${audioMap} -c:a aac -ar 48000 -b:a 192k -f mp4 -movflags faststart ${destM4aPathTmp}`
81
+ ? ` ${videoMap} -c:v libx264 -crf 10` +
82
+ ` ${audioMap} -c:a aac -ar 48000 -b:a 192k -f mp4 -movflags faststart ${destMp4PathTmp}`
86
83
  : ''));
87
84
  await fs_1.promises.rename(destVideoPathTmp, destVideoPath);
88
85
  await fs_1.promises.rename(destAudioPathTmp, destAudioPath);
89
86
  if (destMp4PathTmp) {
90
87
  await fs_1.promises.rename(destMp4PathTmp, destMp4Path);
91
88
  }
92
- if (destM4aPathTmp) {
93
- await fs_1.promises.rename(destM4aPathTmp, destM4aPath);
94
- }
95
89
  }
96
90
  catch (err) {
97
91
  log.error(`Error converting video: ${err.stack}`);
@@ -107,7 +101,6 @@ async function prepareFakeMedia({ videoPath, videoWidth, videoHeight, videoFrame
107
101
  video: destVideoPath,
108
102
  audio: destAudioPath,
109
103
  mp4: destMp4Path,
110
- m4a: destM4aPath,
111
104
  };
112
105
  }
113
106
  //# sourceMappingURL=media.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/media.ts"],"names":[],"mappings":";;AA8BA,4CAwHC;AAtJD,2BAA+C;AAE/C,mCAAyD;AAEzD,MAAM,GAAG,GAAG,IAAA,cAAM,EAAC,kBAAkB,CAAC,CAAA;AAEtC,MAAM,kBAAkB,GAAG,6EAA6E,CAAA;AASxG;;;;;;;;;;;;;;GAcG;AACI,KAAK,UAAU,gBAAgB,CAAC,EACrC,SAAS,EACT,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACT,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,GAYb;IACC,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE;QAC5B,SAAS;QACT,UAAU;QACV,WAAW;QACX,cAAc;QACd,SAAS;QACT,aAAa;QACb,aAAa;QACb,cAAc;QACd,WAAW;QACX,YAAY;KACb,CAAC,CAAA;IACF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACrC,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAA,eAAU,EAAC,SAAS,CAAC,EAAE,CAAC;QAClG,GAAG,CAAC,IAAI,CAAC,oBAAoB,SAAS,4BAA4B,CAAC,CAAA;QACnE,SAAS,GAAG,kBAAkB,CAAA;IAChC,CAAC;IAED,MAAM,aAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,MAAM,IAAI,GAAG,IAAA,cAAM,EAAC,SAAS,CAAC,CAAA;IAE9B,MAAM,aAAa,GAAG,GAAG,cAAc,IAAI,IAAI,IAAI,UAAU,IAAI,WAAW,IAAI,cAAc,OAAO,WAAW,EAAE,CAAA;IAClH,MAAM,aAAa,GAAG,GAAG,cAAc,IAAI,IAAI,MAAM,CAAA;IACrD,MAAM,WAAW,GAAG,YAAY;QAC9B,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,GAAG,cAAc,IAAI,IAAI,IAAI,UAAU,IAAI,WAAW,IAAI,cAAc,SAAS,CAAA;IACrF,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,cAAc,IAAI,IAAI,MAAM,CAAA;IAEvE,IACE,CAAC,IAAA,eAAU,EAAC,aAAa,CAAC;QAC1B,CAAC,IAAA,eAAU,EAAC,aAAa,CAAC;QAC1B,CAAC,WAAW,IAAI,CAAC,IAAA,eAAU,EAAC,WAAW,CAAC,CAAC;QACzC,CAAC,WAAW,IAAI,CAAC,IAAA,eAAU,EAAC,WAAW,CAAC,CAAC;QACzC,CAAC,aAAa,EACd,CAAC;QACD,GAAG,CAAC,IAAI,CACN,cAAc,SAAS,OAAO,aAAa,KAAK,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAChJ,CAAA;QACD,MAAM,gBAAgB,GAAG,GAAG,cAAc,IAAI,IAAI,IAAI,UAAU,IAAI,WAAW,IAAI,cAAc,WAAW,WAAW,EAAE,CAAA;QACzH,MAAM,gBAAgB,GAAG,GAAG,cAAc,IAAI,IAAI,UAAU,CAAA;QAC5D,MAAM,cAAc,GAAG,YAAY;YACjC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,GAAG,cAAc,IAAI,IAAI,IAAI,UAAU,IAAI,WAAW,IAAI,cAAc,aAAa,CAAA;QACzF,MAAM,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,cAAc,IAAI,IAAI,UAAU,CAAA;QAE9E,IAAI,CAAC;YACH,IAAI,MAAM,GAAG,OAAO,SAAS,GAAG,CAAA;YAChC,MAAM,QAAQ,GAAG,UAAU,CAAA;YAC3B,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAA;YAC5E,IAAI,SAAS,KAAK,eAAe,EAAE,CAAC;gBAClC,MAAM;oBACJ,0BAA0B,UAAU,IAAI,WAAW,SAAS,cAAc,cAAc;wBACxF,+DAA+D,CAAA;YACnE,CAAC;iBAAM,IAAI,SAAS,KAAK,eAAe,EAAE,CAAC;gBACzC,MAAM;oBACJ,4BAA4B,UAAU,IAAI,WAAW,SAAS,cAAc,mBAAmB;wBAC/F,iEAAiE,CAAA;YACrE,CAAC;YACD,MAAM,IAAA,uBAAe,EACnB,0CAA0C,MAAM,EAAE;gBAChD,OAAO,UAAU,IAAI,WAAW,EAAE;gBAClC,OAAO,cAAc,EAAE;gBACvB,QAAQ,SAAS,OAAO,aAAa,qBAAqB;gBAC1D,IAAI,QAAQ,IAAI,gBAAgB,EAAE;gBAClC,IAAI,QAAQ,cAAc,gBAAgB,EAAE;gBAC5C,CAAC,cAAc;oBACb,CAAC,CAAC,IAAI,QAAQ,oDAAoD,cAAc,EAAE;wBAChF,IAAI,QAAQ,4DAA4D,cAAc,EAAE;oBAC1F,CAAC,CAAC,EAAE,CAAC,CACV,CAAA;YACD,MAAM,aAAE,CAAC,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;YAChD,MAAM,aAAE,CAAC,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;YAChD,IAAI,cAAc,EAAE,CAAC;gBACnB,MAAM,aAAE,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;YAC9C,CAAC;YACD,IAAI,cAAc,EAAE,CAAC;gBACnB,MAAM,aAAE,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;YAC9C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,2BAA4B,GAAa,CAAC,KAAK,EAAE,CAAC,CAAA;YAC5D,aAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;YAC5D,aAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;YAC5D,IAAI,cAAc,EAAE,CAAC;gBACnB,aAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;YAC5D,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,aAAa;QACpB,KAAK,EAAE,aAAa;QACpB,GAAG,EAAE,WAAW;QAChB,GAAG,EAAE,WAAW;KACjB,CAAA;AACH,CAAC","sourcesContent":["import { existsSync, promises as fs } from 'fs'\n\nimport { logger, runShellCommand, sha256 } from './utils'\n\nconst log = logger('webrtcperf:media')\n\nconst DEFAULT_VIDEO_PATH = 'https://github.com/vpalmisano/webrtcperf/releases/download/v2.0.4/video.mp4'\n\nexport type MediaPath = {\n video: string\n audio: string\n mp4: string\n m4a: string\n}\n\n/**\n * Converts the video file into raw audio and video files.\n * @param {*} config\n * @param {string} config.videoPath the video to convert\n * @param {string} config.videoWidth the output video width\n * @param {string} config.videoHeight the output video height\n * @param {string} config.videoFramerate the output video framerate\n * @param {string} config.videoSeek the seek position in seconds\n * @param {string} config.videoDuration the output video duration in seconds\n * @param {boolean} config.videoCacheRaw if true and the destinations raw files\n * exist on file system, the conversion step is skipped\n * @param {string} config.videoCachePath the destination directory path; if not\n * existing, it will be created\n * @param {string} config.videoFormat the raw video format (y4m or mjpeg)\n */\nexport async function prepareFakeMedia({\n videoPath,\n videoWidth,\n videoHeight,\n videoFramerate,\n videoSeek,\n videoDuration,\n videoCacheRaw,\n videoCachePath,\n videoFormat,\n useFakeMedia,\n}: {\n videoPath: string\n videoWidth: number\n videoHeight: number\n videoFramerate: number\n videoSeek: number\n videoDuration: number\n videoCacheRaw: boolean\n videoCachePath: string\n videoFormat: string\n useFakeMedia: boolean\n}): Promise<MediaPath> {\n log.debug('prepareFakeMedia', {\n videoPath,\n videoWidth,\n videoHeight,\n videoFramerate,\n videoSeek,\n videoDuration,\n videoCacheRaw,\n videoCachePath,\n videoFormat,\n useFakeMedia,\n })\n if (!videoPath) {\n throw new Error('empty video path')\n }\n if (!videoPath.startsWith('http') && !videoPath.startsWith('generate:') && !existsSync(videoPath)) {\n log.warn(`video not found: ${videoPath}, using default test video`)\n videoPath = DEFAULT_VIDEO_PATH\n }\n\n await fs.mkdir(videoCachePath, { recursive: true })\n const name = sha256(videoPath)\n\n const destVideoPath = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.${videoFormat}`\n const destAudioPath = `${videoCachePath}/${name}.wav`\n const destMp4Path = useFakeMedia\n ? ''\n : `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.mp4`\n const destM4aPath = useFakeMedia ? '' : `${videoCachePath}/${name}.m4a`\n\n if (\n !existsSync(destVideoPath) ||\n !existsSync(destAudioPath) ||\n (destMp4Path && !existsSync(destMp4Path)) ||\n (destM4aPath && !existsSync(destM4aPath)) ||\n !videoCacheRaw\n ) {\n log.info(\n `Converting ${videoPath} to ${destVideoPath}, ${destAudioPath}${destMp4Path ? `, ${destMp4Path}` : ''}${destM4aPath ? `, ${destM4aPath}` : ''}`,\n )\n const destVideoPathTmp = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.${videoFormat}`\n const destAudioPathTmp = `${videoCachePath}/${name}.tmp.wav`\n const destMp4PathTmp = useFakeMedia\n ? ''\n : `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.mp4`\n const destM4aPathTmp = useFakeMedia ? '' : `${videoCachePath}/${name}.tmp.m4a`\n\n try {\n let source = `-i \"${videoPath}\"`\n const videoMap = `-map 0:v`\n const audioMap = videoPath.startsWith('generate:') ? '-map 1:a' : '-map 0:a'\n if (videoPath === 'generate:null') {\n source =\n `-f lavfi -i color=size=${videoWidth}x${videoHeight}:rate=${videoFramerate}:color=black` +\n ` -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000`\n } else if (videoPath === 'generate:test') {\n source =\n `-f lavfi -i testsrc=size=${videoWidth}x${videoHeight}:rate=${videoFramerate} -pix_fmt yuv420p` +\n ` -f lavfi -i sine=frequency=220:beep_factor=4:sample_rate=48000`\n }\n await runShellCommand(\n `ffmpeg -loglevel warning -y -threads 0 ${source}` +\n ` -s ${videoWidth}:${videoHeight}` +\n ` -r ${videoFramerate}` +\n ` -ss ${videoSeek} -t ${videoDuration} -shortest -af apad` +\n ` ${videoMap} ${destVideoPathTmp}` +\n ` ${audioMap} -ar 48000 ${destAudioPathTmp}` +\n (destMp4PathTmp\n ? ` ${videoMap} -c:v libx264 -crf 10 -f mp4 -movflags faststart ${destMp4PathTmp}` +\n ` ${audioMap} -c:a aac -ar 48000 -b:a 192k -f mp4 -movflags faststart ${destM4aPathTmp}`\n : ''),\n )\n await fs.rename(destVideoPathTmp, destVideoPath)\n await fs.rename(destAudioPathTmp, destAudioPath)\n if (destMp4PathTmp) {\n await fs.rename(destMp4PathTmp, destMp4Path)\n }\n if (destM4aPathTmp) {\n await fs.rename(destM4aPathTmp, destM4aPath)\n }\n } catch (err) {\n log.error(`Error converting video: ${(err as Error).stack}`)\n fs.unlink(destVideoPathTmp).catch(e => log.debug(e.message))\n fs.unlink(destAudioPathTmp).catch(e => log.debug(e.message))\n if (destMp4PathTmp) {\n fs.unlink(destMp4PathTmp).catch(e => log.debug(e.message))\n }\n throw err\n }\n }\n\n return {\n video: destVideoPath,\n audio: destAudioPath,\n mp4: destMp4Path,\n m4a: destM4aPath,\n }\n}\n"]}
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/media.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, promises as fs } from 'fs'\n\nimport { logger, runShellCommand, sha256 } from './utils'\n\nconst log = logger('webrtcperf:media')\n\nconst DEFAULT_VIDEO_PATH = 'https://github.com/vpalmisano/webrtcperf/releases/download/v2.0.4/video.mp4'\n\nexport type MediaPath = {\n video: string\n audio: string\n mp4: string\n}\n\n/**\n * Converts the video file into raw audio and video files.\n * @param {*} config\n * @param {string} config.videoPath the video to convert\n * @param {string} config.videoWidth the output video width\n * @param {string} config.videoHeight the output video height\n * @param {string} config.videoFramerate the output video framerate\n * @param {string} config.videoSeek the seek position in seconds\n * @param {string} config.videoDuration the output video duration in seconds\n * @param {boolean} config.videoCacheRaw if true and the destinations raw files\n * exist on file system, the conversion step is skipped\n * @param {string} config.videoCachePath the destination directory path; if not\n * existing, it will be created\n * @param {string} config.videoFormat the raw video format (y4m or mjpeg)\n */\nexport async function prepareFakeMedia({\n videoPath,\n videoWidth,\n videoHeight,\n videoFramerate,\n videoSeek,\n videoDuration,\n videoCacheRaw,\n videoCachePath,\n videoFormat,\n useFakeMedia,\n}: {\n videoPath: string\n videoWidth: number\n videoHeight: number\n videoFramerate: number\n videoSeek: number\n videoDuration: number\n videoCacheRaw: boolean\n videoCachePath: string\n videoFormat: string\n useFakeMedia: boolean\n}): Promise<MediaPath> {\n log.debug('prepareFakeMedia', {\n videoPath,\n videoWidth,\n videoHeight,\n videoFramerate,\n videoSeek,\n videoDuration,\n videoCacheRaw,\n videoCachePath,\n videoFormat,\n useFakeMedia,\n })\n if (!videoPath) {\n throw new Error('empty video path')\n }\n if (!videoPath.startsWith('http') && !videoPath.startsWith('generate:') && !existsSync(videoPath)) {\n log.warn(`video not found: ${videoPath}, using default test video`)\n videoPath = DEFAULT_VIDEO_PATH\n }\n\n await fs.mkdir(videoCachePath, { recursive: true })\n const name = sha256(videoPath)\n\n const destVideoPath = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.${videoFormat}`\n const destAudioPath = `${videoCachePath}/${name}.wav`\n const destMp4Path = useFakeMedia\n ? ''\n : `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.mp4`\n\n if (\n !existsSync(destVideoPath) ||\n !existsSync(destAudioPath) ||\n (destMp4Path && !existsSync(destMp4Path)) ||\n !videoCacheRaw\n ) {\n log.info(`Converting ${videoPath} to ${destVideoPath}, ${destAudioPath}${destMp4Path ? `, ${destMp4Path}` : ''}`)\n const destVideoPathTmp = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.${videoFormat}`\n const destAudioPathTmp = `${videoCachePath}/${name}.tmp.wav`\n const destMp4PathTmp = useFakeMedia\n ? ''\n : `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.mp4`\n\n try {\n let source = `-i \"${videoPath}\"`\n const videoMap = `-map 0:v`\n const audioMap = videoPath.startsWith('generate:') ? '-map 1:a' : '-map 0:a'\n if (videoPath === 'generate:null') {\n source =\n `-f lavfi -i color=size=${videoWidth}x${videoHeight}:rate=${videoFramerate}:color=black` +\n ` -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000`\n } else if (videoPath === 'generate:test') {\n source =\n `-f lavfi -i testsrc=size=${videoWidth}x${videoHeight}:rate=${videoFramerate} -pix_fmt yuv420p` +\n ` -f lavfi -i sine=frequency=220:beep_factor=4:sample_rate=48000`\n }\n await runShellCommand(\n `ffmpeg -loglevel warning -y -threads 0 ${source}` +\n ` -s ${videoWidth}:${videoHeight}` +\n ` -r ${videoFramerate}` +\n ` -ss ${videoSeek} -t ${videoDuration} -shortest -af apad` +\n ` ${videoMap} ${destVideoPathTmp}` +\n ` ${audioMap} -ar 48000 ${destAudioPathTmp}` +\n (destMp4PathTmp\n ? ` ${videoMap} -c:v libx264 -crf 10` +\n ` ${audioMap} -c:a aac -ar 48000 -b:a 192k -f mp4 -movflags faststart ${destMp4PathTmp}`\n : ''),\n )\n await fs.rename(destVideoPathTmp, destVideoPath)\n await fs.rename(destAudioPathTmp, destAudioPath)\n if (destMp4PathTmp) {\n await fs.rename(destMp4PathTmp, destMp4Path)\n }\n } catch (err) {\n log.error(`Error converting video: ${(err as Error).stack}`)\n fs.unlink(destVideoPathTmp).catch(e => log.debug(e.message))\n fs.unlink(destAudioPathTmp).catch(e => log.debug(e.message))\n if (destMp4PathTmp) {\n fs.unlink(destMp4PathTmp).catch(e => log.debug(e.message))\n }\n throw err\n }\n }\n\n return {\n video: destVideoPath,\n audio: destAudioPath,\n mp4: destMp4Path,\n }\n}\n"]}
@@ -69,6 +69,7 @@ export declare enum PageStatsNames {
69
69
  /** The screen start frame delay. */
70
70
  screenStartFrameDelay = "screenStartFrameDelay",
71
71
  cpuPressure = "cpuPressure",
72
+ questionAnswerDelay = "questionAnswerDelay",
72
73
  videoWidth = "videoWidth",
73
74
  videoHeight = "videoHeight",
74
75
  videoBufferedTime = "videoBufferedTime",
@@ -81,6 +81,7 @@ var PageStatsNames;
81
81
  /** The screen start frame delay. */
82
82
  PageStatsNames["screenStartFrameDelay"] = "screenStartFrameDelay";
83
83
  PageStatsNames["cpuPressure"] = "cpuPressure";
84
+ PageStatsNames["questionAnswerDelay"] = "questionAnswerDelay";
84
85
  PageStatsNames["videoWidth"] = "videoWidth";
85
86
  PageStatsNames["videoHeight"] = "videoHeight";
86
87
  PageStatsNames["videoBufferedTime"] = "videoBufferedTime";
@@ -1 +1 @@
1
- {"version":3,"file":"rtcstats.js","sourceRoot":"","sources":["../../src/rtcstats.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'assert'\n\nimport { toTitleCase } from './utils'\n\n/**\n * Page stats metric names.\n */\nexport enum PageStatsNames {\n /** The browser processes CPU usage (per page). */\n cpu = 'cpu',\n /** The browser processes memory usage (per page). */\n memory = 'memory',\n /** The tool nodejs CPU usage. */\n nodeCpu = 'nodeCpu',\n /** The tool nodejs memory usage. */\n nodeMemory = 'nodeMemory',\n /** The system total CPU usage. */\n usedCpu = 'usedCpu',\n /** The system total memory usage. */\n usedMemory = 'usedMemory',\n /** The system total GPU usage. */\n usedGpu = 'usedGpu',\n /** The page CPU usage. */\n pageCpu = 'pageCpu',\n /** The page memory usage. */\n pageMemory = 'pageMemory',\n\n /** The opened pages count. */\n pages = 'pages',\n /** The current opened PeerConnections. */\n peerConnections = 'peerConnections',\n /** The maximum PeerConnections connected duration. */\n peerConnectionConnectionTime = 'peerConnectionConnectionTime',\n /** The maximum PeerConnections disconnection duration. */\n peerConnectionDisconnectionTime = 'peerConnectionDisconnectionTime',\n /** The total created PeerConnections. */\n peerConnectionsCreated = 'peerConnectionsCreated',\n /** The total connected PeerConnections. */\n peerConnectionsConnected = 'peerConnectionsConnected',\n /** The total closed PeerConnections. */\n peerConnectionsClosed = 'peerConnectionsClosed',\n /** The total disconnected PeerConnections. */\n peerConnectionsDisconnected = 'peerConnectionsDisconnected',\n /** The total failed PeerConnections. */\n peerConnectionsFailed = 'peerConnectionsFailed',\n /** The total delay from PeerConnections creation to connection. */\n peerConnectionsDelay = 'peerConnectionsDelay',\n\n /** The page errors count. */\n errors = 'errors',\n /** The page warnings count. */\n warnings = 'warnings',\n\n /** The page total HTTP sent bytes. */\n httpSentBytes = 'httpSentBytes',\n /** The page total HTTP received bytes. */\n httpRecvBytes = 'httpRecvBytes',\n /** The page HTTP receive latency. */\n httpRecvLatency = 'httpRecvLatency',\n\n /** The page total WebSocket sent bytes. */\n wsSentBytes = 'wsSentBytes',\n /** The page total WebSocket received bytes. */\n wsRecvBytes = 'wsRecvBytes',\n /** The page WebSocket receive latency. */\n wsRecvLatency = 'wsRecvLatency',\n\n /** The audio end to end total delay. */\n audioEndToEndDelay = 'audioEndToEndDelay',\n /** The audio start frame delay. */\n audioStartFrameDelay = 'audioStartFrameDelay',\n\n /** The video end to end total delay. */\n videoEndToEndDelay = 'videoEndToEndDelay',\n /** The video start frame delay. */\n videoStartFrameDelay = 'videoStartFrameDelay',\n\n /** The screen end to end total delay. */\n screenEndToEndDelay = 'screenEndToEndDelay',\n /** The screen start frame delay. */\n screenStartFrameDelay = 'screenStartFrameDelay',\n\n cpuPressure = 'cpuPressure',\n\n videoWidth = 'videoWidth',\n videoHeight = 'videoHeight',\n videoBufferedTime = 'videoBufferedTime',\n videoPlayingTime = 'videoPlayingTime',\n videoBufferingTime = 'videoBufferingTime',\n videoBufferingEvents = 'videoBufferingEvents',\n\n /** The throttle upload rate limitation. */\n throttleUpRate = 'throttleUpRate',\n /** The throttle upload delay. */\n throttleUpDelay = 'throttleUpDelay',\n /** The throttle upload packet loss. */\n throttleUpLoss = 'throttleUpLoss',\n /** The throttle upload packet queue. */\n throttleUpQueue = 'throttleUpQueue',\n\n /** The throttle download rate limitation. */\n throttleDownRate = 'throttleDownRate',\n /** The throttle download delay. */\n throttleDownDelay = 'throttleDownDelay',\n /** The throttle download packet loss. */\n throttleDownLoss = 'throttleDownLoss',\n /** The throttle download packet queue. */\n throttleDownQueue = 'throttleDownQueue',\n}\n\n/**\n * RTC metrics collected by the page helper scripts and related to each\n * track object created by PeerConnections.\n */\nexport enum RtcStatsMetricNames {\n /** The sent audio codec. */\n audioSentCodec = 'audioSentCodec',\n /** The total sent audio bytes. */\n audioSentBytes = 'audioSentBytes',\n /** The sent audio packets. */\n audioSentPackets = 'audioSentPackets',\n /** The sent audio bitrates. */\n audioSentBitrates = 'audioSentBitrates',\n /** The send audio lost packets. */\n audioSentPacketsLost = 'audioSentPacketsLost',\n //'audioSentPacketsLostCount',\n /** The total audio NACK received by the sender. */\n audioSentNackCountRecv = 'audioSentNackCountRecv',\n /** The sent audio round trip time. */\n audioSentRoundTripTime = 'audioSentRoundTripTime',\n /** The sent audio jitter. */\n audioSentJitter = 'audioSentJitter',\n /** The audio RTC transport round trip time. */\n audioSentTransportRoundTripTime = 'audioSentTransportRoundTripTime',\n /** The sent audio encoding max bitrate. */\n audioSentMaxBitrate = 'audioSentMaxBitrate',\n /** The sent audio RTX packets. */\n audioSentRetransmittedPackets = 'audioSentRetransmittedPackets',\n\n /** The sent video codec. */\n videoSentCodec = 'videoSentCodec',\n /** The FIR requests received by the video sender. */\n videoFirCountReceived = 'videoFirCountReceived',\n /** The PLI requests received by the video sender. */\n videoPliCountReceived = 'videoPliCountReceived',\n /** The sent video encode latency. */\n videoEncodeLatency = 'videoEncodeLatency',\n /** The sent video latency. */\n videoSentLatency = 'videoSentLatency',\n /** The sent video bandwidth quality limitations. */\n videoQualityLimitationBandwidth = 'videoQualityLimitationBandwidth',\n /** The sent video cpu quality limitations. */\n videoQualityLimitationCpu = 'videoQualityLimitationCpu',\n /** The sent video total resolution changes for quality limitations. */\n videoQualityLimitationResolutionChanges = 'videoQualityLimitationResolutionChanges',\n /** The sent video Simulcast active spatial layers. */\n videoSentActiveEncodings = 'videoSentActiveEncodings',\n /** The sent video bitrates. */\n videoSentBitrates = 'videoSentBitrates',\n /** The sent video bytes. */\n videoSentBytes = 'videoSentBytes',\n /** The sent video packets. */\n videoSentPackets = 'videoSentPackets',\n /** The sent video frames. */\n videoSentFrames = 'videoSentFrames',\n /** The sent video framerate. */\n videoSentFps = 'videoSentFps',\n /** The sent video width. */\n videoSentWidth = 'videoSentWidth',\n /** The sent video height. */\n videoSentHeight = 'videoSentHeight',\n /** The sent video encoding max bitrate. */\n videoSentMaxBitrate = 'videoSentMaxBitrate',\n //'videoSentPackets',\n /** The sent video lost packets. */\n videoSentPacketsLost = 'videoSentPacketsLost',\n //'videoSentPacketsLostCount',\n /** The NACK count received by video sender. */\n videoSentNackCountRecv = 'videoSentNackCountRecv',\n /** The sent video round trip time. */\n videoSentRoundTripTime = 'videoSentRoundTripTime',\n /** The transport send video round trip time. */\n videoSentTransportRoundTripTime = 'videoSentTransportRoundTripTime',\n /** The video sent jitter. */\n videoSentJitter = 'videoSentJitter',\n /** The sent video RTX packets. */\n videoSentRetransmittedPackets = 'videoSentRetransmittedPackets',\n\n /** The sent screen codec. */\n screenSentCodec = 'screenSentCodec',\n /** The received FIR from screen sender. */\n screenFirCountReceived = 'screenFirCountReceived',\n /** The received PLI from screen sender. */\n screenPliCountReceived = 'screenPliCountReceived',\n /** The sent screen encode latency. */\n screenEncodeLatency = 'screenEncodeLatency',\n /** The sent screen latency. */\n screenSentLatency = 'screenSentLatency',\n /** The sent screen bandwidth quality limitation. */\n screenQualityLimitationBandwidth = 'screenQualityLimitationBandwidth',\n /** The sent screen cpu quality limitation. */\n screenQualityLimitationCpu = 'screenQualityLimitationCpu',\n /** The sent screen resolustion changes caused by quality limitation. */\n screenQualityLimitationResolutionChanges = 'screenQualityLimitationResolutionChanges',\n /** The sent screen active Simulcast spatial layers. */\n screenSentActiveEncodings = 'screenSentActiveEncodings',\n /** The sent screen bitrates. */\n screenSentBitrates = 'screenSentBitrates',\n /** The sent screen bytes. */\n screenSentBytes = 'screenSentBytes',\n /** The sent screen packets. */\n screenSentPackets = 'screenSentPackets',\n /** The sent screen frames. */\n screenSentFrames = 'screenSentFrames',\n /** The sent screen framerate. */\n screenSentFps = 'screenSentFps',\n /** The sent screen width. */\n screenSentWidth = 'screenSentWidth',\n /** The sent screen height. */\n screenSentHeight = 'screenSentHeight',\n /** The sent screen encoding max bitrate. */\n screenSentMaxBitrate = 'screenSentMaxBitrate',\n //'screenSentPackets',\n /** The sent screen lost packets. */\n screenSentPacketsLost = 'screenSentPacketsLost',\n //'screenSentPacketsLostCount',\n /** The NACK count received by screen sender. */\n screenSentNackCountRecv = 'screenSentNackCountRecv',\n /** The sent screen round trip time. */\n screenSentRoundTripTime = 'screenSentRoundTripTime',\n /** The transport sent screen round trip time. */\n screenSentTransportRoundTripTime = 'screenSentTransportRoundTripTime',\n /** The screen sent jitter. */\n screenSentJitter = 'screenSentJitter',\n /** The screen audio RTX packets. */\n screenSentRetransmittedPackets = 'screenSentRetransmittedPackets',\n\n // inbound audio,\n audioRecvCodec = 'audioRecvCodec',\n audioRecvBytes = 'audioRecvBytes',\n audioRecvAvgJitterBufferDelay = 'audioRecvAvgJitterBufferDelay',\n audioRecvBitrates = 'audioRecvBitrates',\n audioRecvJitter = 'audioRecvJitter',\n audioRecvRoundTripTime = 'audioRecvRoundTripTime',\n audioRecvPackets = 'audioRecvPackets',\n audioRecvPacketsLost = 'audioRecvPacketsLost', // TODO: remove this.\n audioRecvLostPackets = 'audioRecvLostPackets',\n audioRecvPacketsLossRate = 'audioRecvPacketsLossRate',\n audioRecvRetransmittedPackets = 'audioRecvRetransmittedPackets',\n audioRecvNackCountSent = 'audioRecvNackCountSent',\n audioRecvLevel = 'audioRecvLevel',\n audioRecvTotalSamplesReceived = 'audioRecvTotalSamplesReceived',\n audioRecvConcealedSamples = 'audioRecvConcealedSamples',\n audioRecvConcealmentEvents = 'audioRecvConcealmentEvents',\n audioRecvInsertedSamplesForDeceleration = 'audioRecvInsertedSamplesForDeceleration',\n audioRecvRemovedSamplesForAcceleration = 'audioRecvRemovedSamplesForAcceleration',\n audioRecvEndToEndDelay = 'audioRecvEndToEndDelay',\n // inbound video,\n videoRecvCodec = 'videoRecvCodec',\n videoFirCountSent = 'videoFirCountSent',\n videoPliCountSent = 'videoPliCountSent',\n videoDecodeLatency = 'videoDecodeLatency',\n videoFramesDecoded = 'videoFramesDecoded',\n videoFramesDropped = 'videoFramesDropped',\n videoRecvFrames = 'videoRecvFrames',\n videoRecvFps = 'videoRecvFps',\n videoRecvAvgJitterBufferDelay = 'videoRecvAvgJitterBufferDelay',\n videoRecvBitrates = 'videoRecvBitrates',\n videoRecvBytes = 'videoRecvBytes',\n videoRecvHeight = 'videoRecvHeight',\n videoRecvJitter = 'videoRecvJitter',\n videoRecvRoundTripTime = 'videoRecvRoundTripTime',\n videoRecvPackets = 'videoRecvPackets',\n videoRecvLostPackets = 'videoRecvLostPackets',\n videoRecvPacketsLost = 'videoRecvPacketsLost', // TODO: remove this.\n videoRecvPacketsLossRate = 'videoRecvPacketsLossRate',\n videoRecvRetransmittedPackets = 'videoRecvRetransmittedPackets',\n videoRecvNackCountSent = 'videoRecvNackCountSent',\n videoRecvWidth = 'videoRecvWidth',\n videoRecvFrameRate = 'videoRecvFrameRate',\n //'videoTotalDecodeTime',\n videoTotalFreezesDuration = 'videoTotalFreezesDuration',\n videoRecvEndToEndDelay = 'videoRecvEndToEndDelay',\n // inbound screen,\n screenRecvCodec = 'screenRecvCodec',\n screenFirCountSent = 'screenFirCountSent',\n screenPliCountSent = 'screenPliCountSent',\n screenDecodeLatency = 'screenDecodeLatency',\n screenFramesDecoded = 'screenFramesDecoded',\n screenFramesDropped = 'screenFramesDropped',\n screenRecvFrames = 'screenRecvFrames',\n screenRecvFps = 'screenRecvFps',\n screenRecvAvgJitterBufferDelay = 'screenRecvAvgJitterBufferDelay',\n screenRecvBitrates = 'screenRecvBitrates',\n screenRecvBytes = 'screenRecvBytes',\n screenRecvHeight = 'screenRecvHeight',\n screenRecvJitter = 'screenRecvJitter',\n screenRecvRoundTripTime = 'screenRecvRoundTripTime',\n screenRecvPackets = 'screenRecvPackets',\n screenRecvLostPackets = 'screenRecvLostPackets',\n screenRecvPacketsLost = 'screenRecvPacketsLost', // TODO: remove this.\n screenRecvPacketsLossRate = 'screenRecvPacketsLossRate',\n screenRecvRetransmittedPackets = 'screenRecvRetransmittedPackets',\n screenRecvNackCountSent = 'screenRecvNackCountSent',\n screenRecvWidth = 'screenRecvWidth',\n screenRecvFrameRate = 'screenRecvFrameRate',\n //'screenTotalDecodeTime',\n screenTotalFreezesDuration = 'screenTotalFreezesDuration',\n screenRecvEndToEndDelay = 'screenRecvEndToEndDelay',\n /** The transport availableOutgoingBitrate stat. */\n transportSentAvailableOutgoingBitrate = 'transportSentAvailableOutgoingBitrate',\n}\n\n/**\n * The RTC stats collection indexed by {@link RtcStatsMetricNames}.\n *\n * Each {@link RtcStatsMetricNames} record points to an object indexed by\n * `trackId:hostName:codec`, where:\n * - `trackId`: The RTC getStats track identifier.\n * - `hostName`: The remote endpoint IP address or hostname.\n * - `codec`: The track codec.\n */\nexport type RtcStats = Record<RtcStatsMetricNames, Record<string, number | string>>\n\nconst RtcStatsMetrics = Object.keys(RtcStatsMetricNames)\n\nfunction setStats(stats: RtcStats, name: RtcStatsMetricNames, key: string, value?: number | string): void {\n assert(RtcStatsMetrics.includes(name), `Unknown stat name: ${name}`)\n if (value === undefined) return\n if (!stats[name]) {\n stats[name] = {}\n }\n stats[name][key] = value\n}\n\nexport function rtcStatKey({\n pageIndex,\n trackId,\n hostName,\n codec,\n participantName,\n}: {\n pageIndex?: number\n trackId?: string\n hostName?: string\n codec?: string\n participantName?: string\n}): string {\n return [pageIndex ?? '', participantName || '', hostName || 'unknown', codec || '', trackId || ''].join(':')\n}\n\nexport function parseRtStatKey(key: string): {\n pageIndex?: number\n trackId?: string\n hostName: string\n codec?: string\n participantName?: string\n} {\n const [pageIndex, participantName, hostName, codec, trackId] = key.split(':', 5)\n return {\n pageIndex: pageIndex ? parseInt(pageIndex) : undefined,\n trackId: trackId || undefined,\n hostName: hostName || 'unknown',\n codec: codec || undefined,\n participantName: participantName || undefined,\n }\n}\n\n/**\n * Updates the {@link RtcStats} object with the collected track values.\n */\nexport function updateRtcStats(\n stats: RtcStats,\n pageIndex: number,\n trackId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any,\n signalingHost?: string,\n participantName?: string,\n): void {\n const {\n enabled,\n inboundRtp,\n outboundRtp,\n remoteAddress,\n videoSentActiveEncodings,\n sentMaxBitrate,\n isDisplay,\n codec,\n availableOutgoingBitrate,\n } = value\n const hostName = signalingHost || remoteAddress\n const key = rtcStatKey({\n pageIndex,\n trackId,\n hostName,\n codec,\n participantName,\n })\n //log.log(`updateRtcStats`, {enabled, signalingHost, remoteAddress, isDisplay, key})\n // inbound\n if (inboundRtp) {\n const prefix = inboundRtp.kind === 'video' ? (isDisplay ? 'screen' : 'video') : 'audio'\n setStats(stats, (prefix + 'RecvCodec') as RtcStatsMetricNames, key, codec)\n if (enabled) {\n setStats(stats, (prefix + 'RecvAvgJitterBufferDelay') as RtcStatsMetricNames, key, inboundRtp.jitterBuffer)\n setStats(stats, (prefix + 'RecvBitrates') as RtcStatsMetricNames, key, inboundRtp.bitrate)\n setStats(stats, (prefix + 'RecvBytes') as RtcStatsMetricNames, key, inboundRtp.bytesReceived)\n setStats(stats, (prefix + 'RecvJitter') as RtcStatsMetricNames, key, inboundRtp.jitter)\n setStats(stats, (prefix + 'RecvRoundTripTime') as RtcStatsMetricNames, key, inboundRtp.transportRoundTripTime)\n setStats(stats, (prefix + 'RecvPackets') as RtcStatsMetricNames, key, inboundRtp.packetsReceived)\n setStats(\n stats,\n (prefix + 'RecvRetransmittedPackets') as RtcStatsMetricNames,\n key,\n inboundRtp.retransmittedPacketsReceived,\n )\n // TODO: remove this.\n setStats(stats, (prefix + 'RecvPacketsLost') as RtcStatsMetricNames, key, inboundRtp.packetsLossRate)\n setStats(stats, (prefix + 'RecvPacketsLossRate') as RtcStatsMetricNames, key, inboundRtp.packetsLossRate)\n setStats(stats, (prefix + 'RecvLostPackets') as RtcStatsMetricNames, key, inboundRtp.packetsLost)\n setStats(stats, (prefix + 'RecvNackCountSent') as RtcStatsMetricNames, key, inboundRtp.nackCount)\n setStats(stats, (prefix + 'RecvEndToEndDelay') as RtcStatsMetricNames, key, inboundRtp.endToEndDelay)\n if (inboundRtp.kind === 'audio') {\n ;[\n 'audioLevel',\n 'totalSamplesReceived',\n 'concealedSamples',\n 'concealmentEvents',\n 'insertedSamplesForDeceleration',\n 'removedSamplesForAcceleration',\n ].forEach(name => {\n setStats(\n stats,\n (prefix + 'Recv' + toTitleCase(name.replace('audio', ''))) as RtcStatsMetricNames,\n key,\n inboundRtp[name],\n )\n })\n }\n if (inboundRtp.kind === 'video' && inboundRtp.keyFramesDecoded > 0) {\n setStats(stats, (prefix + 'FramesDecoded') as RtcStatsMetricNames, key, inboundRtp.framesDecoded)\n setStats(stats, (prefix + 'FramesDropped') as RtcStatsMetricNames, key, inboundRtp.framesDropped)\n setStats(stats, (prefix + 'RecvFrames') as RtcStatsMetricNames, key, inboundRtp.framesReceived)\n setStats(stats, (prefix + 'RecvFps') as RtcStatsMetricNames, key, inboundRtp.framesPerSecond)\n setStats(stats, (prefix + 'RecvHeight') as RtcStatsMetricNames, key, inboundRtp.frameHeight)\n setStats(stats, (prefix + 'RecvWidth') as RtcStatsMetricNames, key, inboundRtp.frameWidth)\n setStats(stats, (prefix + 'RecvFrameRate') as RtcStatsMetricNames, key, inboundRtp.frameRate)\n //setStats(stats, prefix + 'TotalDecodeTime', key, inboundRtp.totalDecodeTime)\n setStats(stats, (prefix + 'FirCountSent') as RtcStatsMetricNames, key, inboundRtp.firCount)\n setStats(stats, (prefix + 'PliCountSent') as RtcStatsMetricNames, key, inboundRtp.pliCount)\n setStats(stats, (prefix + 'DecodeLatency') as RtcStatsMetricNames, key, inboundRtp.decodeLatency)\n setStats(stats, (prefix + 'TotalFreezesDuration') as RtcStatsMetricNames, key, inboundRtp.totalFreezesDuration)\n }\n }\n }\n // outbound\n if (outboundRtp) {\n // log.log('outboundRtp', isDisplay, JSON.stringify(outboundRtp, null, 2));\n const prefix = outboundRtp.kind === 'video' ? (isDisplay ? 'screen' : 'video') : 'audio'\n setStats(stats, (prefix + 'SentCodec') as RtcStatsMetricNames, key, codec)\n if (enabled) {\n setStats(stats, (prefix + 'SentBitrates') as RtcStatsMetricNames, key, outboundRtp.bitrate)\n setStats(\n stats,\n (prefix + 'SentBytes') as RtcStatsMetricNames,\n key,\n outboundRtp.bytesSent + outboundRtp.headerBytesSent,\n )\n setStats(stats, (prefix + 'SentPackets') as RtcStatsMetricNames, key, outboundRtp.packetsSent)\n setStats(stats, (prefix + 'SentPacketsLost') as RtcStatsMetricNames, key, outboundRtp.packetsLossRate)\n setStats(stats, (prefix + 'SentNackCountRecv') as RtcStatsMetricNames, key, outboundRtp.nackCount)\n //setStats(stats, prefix + 'SentPacketsLostCount', key, outboundRtp.packetsLost)\n setStats(stats, (prefix + 'SentRoundTripTime') as RtcStatsMetricNames, key, outboundRtp.roundTripTime)\n setStats(stats, (prefix + 'SentJitter') as RtcStatsMetricNames, key, outboundRtp.jitter)\n setStats(\n stats,\n (prefix + 'SentTransportRoundTripTime') as RtcStatsMetricNames,\n key,\n outboundRtp.transportRoundTripTime,\n )\n setStats(stats, 'transportSentAvailableOutgoingBitrate' as RtcStatsMetricNames, key, availableOutgoingBitrate)\n setStats(stats, (prefix + 'SentMaxBitrate') as RtcStatsMetricNames, key, sentMaxBitrate)\n setStats(\n stats,\n (prefix + 'SentRetransmittedPackets') as RtcStatsMetricNames,\n key,\n outboundRtp.retransmittedPacketsSent,\n )\n if (outboundRtp.kind === 'video') {\n setStats(stats, (prefix + 'SentActiveEncodings') as RtcStatsMetricNames, key, videoSentActiveEncodings)\n setStats(\n stats,\n (prefix + 'QualityLimitationResolutionChanges') as RtcStatsMetricNames,\n key,\n outboundRtp.qualityLimitationResolutionChanges,\n )\n setStats(stats, (prefix + 'QualityLimitationCpu') as RtcStatsMetricNames, key, outboundRtp.qualityLimitationCpu)\n setStats(\n stats,\n (prefix + 'QualityLimitationBandwidth') as RtcStatsMetricNames,\n key,\n outboundRtp.qualityLimitationBandwidth,\n )\n setStats(stats, (prefix + 'SentWidth') as RtcStatsMetricNames, key, outboundRtp.frameWidth)\n setStats(stats, (prefix + 'SentHeight') as RtcStatsMetricNames, key, outboundRtp.frameHeight)\n setStats(stats, (prefix + 'SentFrames') as RtcStatsMetricNames, key, outboundRtp.framesSent)\n setStats(stats, (prefix + 'SentFps') as RtcStatsMetricNames, key, outboundRtp.framesPerSecond)\n setStats(stats, (prefix + 'FirCountReceived') as RtcStatsMetricNames, key, outboundRtp.firCountReceived)\n setStats(stats, (prefix + 'PliCountReceived') as RtcStatsMetricNames, key, outboundRtp.pliCountReceived)\n setStats(stats, (prefix + 'EncodeLatency') as RtcStatsMetricNames, key, outboundRtp.encodeLatency)\n setStats(stats, (prefix + 'SentLatency') as RtcStatsMetricNames, key, outboundRtp.sentLatency)\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"rtcstats.js","sourceRoot":"","sources":["../../src/rtcstats.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'assert'\n\nimport { toTitleCase } from './utils'\n\n/**\n * Page stats metric names.\n */\nexport enum PageStatsNames {\n /** The browser processes CPU usage (per page). */\n cpu = 'cpu',\n /** The browser processes memory usage (per page). */\n memory = 'memory',\n /** The tool nodejs CPU usage. */\n nodeCpu = 'nodeCpu',\n /** The tool nodejs memory usage. */\n nodeMemory = 'nodeMemory',\n /** The system total CPU usage. */\n usedCpu = 'usedCpu',\n /** The system total memory usage. */\n usedMemory = 'usedMemory',\n /** The system total GPU usage. */\n usedGpu = 'usedGpu',\n /** The page CPU usage. */\n pageCpu = 'pageCpu',\n /** The page memory usage. */\n pageMemory = 'pageMemory',\n\n /** The opened pages count. */\n pages = 'pages',\n /** The current opened PeerConnections. */\n peerConnections = 'peerConnections',\n /** The maximum PeerConnections connected duration. */\n peerConnectionConnectionTime = 'peerConnectionConnectionTime',\n /** The maximum PeerConnections disconnection duration. */\n peerConnectionDisconnectionTime = 'peerConnectionDisconnectionTime',\n /** The total created PeerConnections. */\n peerConnectionsCreated = 'peerConnectionsCreated',\n /** The total connected PeerConnections. */\n peerConnectionsConnected = 'peerConnectionsConnected',\n /** The total closed PeerConnections. */\n peerConnectionsClosed = 'peerConnectionsClosed',\n /** The total disconnected PeerConnections. */\n peerConnectionsDisconnected = 'peerConnectionsDisconnected',\n /** The total failed PeerConnections. */\n peerConnectionsFailed = 'peerConnectionsFailed',\n /** The total delay from PeerConnections creation to connection. */\n peerConnectionsDelay = 'peerConnectionsDelay',\n\n /** The page errors count. */\n errors = 'errors',\n /** The page warnings count. */\n warnings = 'warnings',\n\n /** The page total HTTP sent bytes. */\n httpSentBytes = 'httpSentBytes',\n /** The page total HTTP received bytes. */\n httpRecvBytes = 'httpRecvBytes',\n /** The page HTTP receive latency. */\n httpRecvLatency = 'httpRecvLatency',\n\n /** The page total WebSocket sent bytes. */\n wsSentBytes = 'wsSentBytes',\n /** The page total WebSocket received bytes. */\n wsRecvBytes = 'wsRecvBytes',\n /** The page WebSocket receive latency. */\n wsRecvLatency = 'wsRecvLatency',\n\n /** The audio end to end total delay. */\n audioEndToEndDelay = 'audioEndToEndDelay',\n /** The audio start frame delay. */\n audioStartFrameDelay = 'audioStartFrameDelay',\n\n /** The video end to end total delay. */\n videoEndToEndDelay = 'videoEndToEndDelay',\n /** The video start frame delay. */\n videoStartFrameDelay = 'videoStartFrameDelay',\n\n /** The screen end to end total delay. */\n screenEndToEndDelay = 'screenEndToEndDelay',\n /** The screen start frame delay. */\n screenStartFrameDelay = 'screenStartFrameDelay',\n\n cpuPressure = 'cpuPressure',\n questionAnswerDelay = 'questionAnswerDelay',\n\n videoWidth = 'videoWidth',\n videoHeight = 'videoHeight',\n videoBufferedTime = 'videoBufferedTime',\n videoPlayingTime = 'videoPlayingTime',\n videoBufferingTime = 'videoBufferingTime',\n videoBufferingEvents = 'videoBufferingEvents',\n\n /** The throttle upload rate limitation. */\n throttleUpRate = 'throttleUpRate',\n /** The throttle upload delay. */\n throttleUpDelay = 'throttleUpDelay',\n /** The throttle upload packet loss. */\n throttleUpLoss = 'throttleUpLoss',\n /** The throttle upload packet queue. */\n throttleUpQueue = 'throttleUpQueue',\n\n /** The throttle download rate limitation. */\n throttleDownRate = 'throttleDownRate',\n /** The throttle download delay. */\n throttleDownDelay = 'throttleDownDelay',\n /** The throttle download packet loss. */\n throttleDownLoss = 'throttleDownLoss',\n /** The throttle download packet queue. */\n throttleDownQueue = 'throttleDownQueue',\n}\n\n/**\n * RTC metrics collected by the page helper scripts and related to each\n * track object created by PeerConnections.\n */\nexport enum RtcStatsMetricNames {\n /** The sent audio codec. */\n audioSentCodec = 'audioSentCodec',\n /** The total sent audio bytes. */\n audioSentBytes = 'audioSentBytes',\n /** The sent audio packets. */\n audioSentPackets = 'audioSentPackets',\n /** The sent audio bitrates. */\n audioSentBitrates = 'audioSentBitrates',\n /** The send audio lost packets. */\n audioSentPacketsLost = 'audioSentPacketsLost',\n //'audioSentPacketsLostCount',\n /** The total audio NACK received by the sender. */\n audioSentNackCountRecv = 'audioSentNackCountRecv',\n /** The sent audio round trip time. */\n audioSentRoundTripTime = 'audioSentRoundTripTime',\n /** The sent audio jitter. */\n audioSentJitter = 'audioSentJitter',\n /** The audio RTC transport round trip time. */\n audioSentTransportRoundTripTime = 'audioSentTransportRoundTripTime',\n /** The sent audio encoding max bitrate. */\n audioSentMaxBitrate = 'audioSentMaxBitrate',\n /** The sent audio RTX packets. */\n audioSentRetransmittedPackets = 'audioSentRetransmittedPackets',\n\n /** The sent video codec. */\n videoSentCodec = 'videoSentCodec',\n /** The FIR requests received by the video sender. */\n videoFirCountReceived = 'videoFirCountReceived',\n /** The PLI requests received by the video sender. */\n videoPliCountReceived = 'videoPliCountReceived',\n /** The sent video encode latency. */\n videoEncodeLatency = 'videoEncodeLatency',\n /** The sent video latency. */\n videoSentLatency = 'videoSentLatency',\n /** The sent video bandwidth quality limitations. */\n videoQualityLimitationBandwidth = 'videoQualityLimitationBandwidth',\n /** The sent video cpu quality limitations. */\n videoQualityLimitationCpu = 'videoQualityLimitationCpu',\n /** The sent video total resolution changes for quality limitations. */\n videoQualityLimitationResolutionChanges = 'videoQualityLimitationResolutionChanges',\n /** The sent video Simulcast active spatial layers. */\n videoSentActiveEncodings = 'videoSentActiveEncodings',\n /** The sent video bitrates. */\n videoSentBitrates = 'videoSentBitrates',\n /** The sent video bytes. */\n videoSentBytes = 'videoSentBytes',\n /** The sent video packets. */\n videoSentPackets = 'videoSentPackets',\n /** The sent video frames. */\n videoSentFrames = 'videoSentFrames',\n /** The sent video framerate. */\n videoSentFps = 'videoSentFps',\n /** The sent video width. */\n videoSentWidth = 'videoSentWidth',\n /** The sent video height. */\n videoSentHeight = 'videoSentHeight',\n /** The sent video encoding max bitrate. */\n videoSentMaxBitrate = 'videoSentMaxBitrate',\n //'videoSentPackets',\n /** The sent video lost packets. */\n videoSentPacketsLost = 'videoSentPacketsLost',\n //'videoSentPacketsLostCount',\n /** The NACK count received by video sender. */\n videoSentNackCountRecv = 'videoSentNackCountRecv',\n /** The sent video round trip time. */\n videoSentRoundTripTime = 'videoSentRoundTripTime',\n /** The transport send video round trip time. */\n videoSentTransportRoundTripTime = 'videoSentTransportRoundTripTime',\n /** The video sent jitter. */\n videoSentJitter = 'videoSentJitter',\n /** The sent video RTX packets. */\n videoSentRetransmittedPackets = 'videoSentRetransmittedPackets',\n\n /** The sent screen codec. */\n screenSentCodec = 'screenSentCodec',\n /** The received FIR from screen sender. */\n screenFirCountReceived = 'screenFirCountReceived',\n /** The received PLI from screen sender. */\n screenPliCountReceived = 'screenPliCountReceived',\n /** The sent screen encode latency. */\n screenEncodeLatency = 'screenEncodeLatency',\n /** The sent screen latency. */\n screenSentLatency = 'screenSentLatency',\n /** The sent screen bandwidth quality limitation. */\n screenQualityLimitationBandwidth = 'screenQualityLimitationBandwidth',\n /** The sent screen cpu quality limitation. */\n screenQualityLimitationCpu = 'screenQualityLimitationCpu',\n /** The sent screen resolustion changes caused by quality limitation. */\n screenQualityLimitationResolutionChanges = 'screenQualityLimitationResolutionChanges',\n /** The sent screen active Simulcast spatial layers. */\n screenSentActiveEncodings = 'screenSentActiveEncodings',\n /** The sent screen bitrates. */\n screenSentBitrates = 'screenSentBitrates',\n /** The sent screen bytes. */\n screenSentBytes = 'screenSentBytes',\n /** The sent screen packets. */\n screenSentPackets = 'screenSentPackets',\n /** The sent screen frames. */\n screenSentFrames = 'screenSentFrames',\n /** The sent screen framerate. */\n screenSentFps = 'screenSentFps',\n /** The sent screen width. */\n screenSentWidth = 'screenSentWidth',\n /** The sent screen height. */\n screenSentHeight = 'screenSentHeight',\n /** The sent screen encoding max bitrate. */\n screenSentMaxBitrate = 'screenSentMaxBitrate',\n //'screenSentPackets',\n /** The sent screen lost packets. */\n screenSentPacketsLost = 'screenSentPacketsLost',\n //'screenSentPacketsLostCount',\n /** The NACK count received by screen sender. */\n screenSentNackCountRecv = 'screenSentNackCountRecv',\n /** The sent screen round trip time. */\n screenSentRoundTripTime = 'screenSentRoundTripTime',\n /** The transport sent screen round trip time. */\n screenSentTransportRoundTripTime = 'screenSentTransportRoundTripTime',\n /** The screen sent jitter. */\n screenSentJitter = 'screenSentJitter',\n /** The screen audio RTX packets. */\n screenSentRetransmittedPackets = 'screenSentRetransmittedPackets',\n\n // inbound audio,\n audioRecvCodec = 'audioRecvCodec',\n audioRecvBytes = 'audioRecvBytes',\n audioRecvAvgJitterBufferDelay = 'audioRecvAvgJitterBufferDelay',\n audioRecvBitrates = 'audioRecvBitrates',\n audioRecvJitter = 'audioRecvJitter',\n audioRecvRoundTripTime = 'audioRecvRoundTripTime',\n audioRecvPackets = 'audioRecvPackets',\n audioRecvPacketsLost = 'audioRecvPacketsLost', // TODO: remove this.\n audioRecvLostPackets = 'audioRecvLostPackets',\n audioRecvPacketsLossRate = 'audioRecvPacketsLossRate',\n audioRecvRetransmittedPackets = 'audioRecvRetransmittedPackets',\n audioRecvNackCountSent = 'audioRecvNackCountSent',\n audioRecvLevel = 'audioRecvLevel',\n audioRecvTotalSamplesReceived = 'audioRecvTotalSamplesReceived',\n audioRecvConcealedSamples = 'audioRecvConcealedSamples',\n audioRecvConcealmentEvents = 'audioRecvConcealmentEvents',\n audioRecvInsertedSamplesForDeceleration = 'audioRecvInsertedSamplesForDeceleration',\n audioRecvRemovedSamplesForAcceleration = 'audioRecvRemovedSamplesForAcceleration',\n audioRecvEndToEndDelay = 'audioRecvEndToEndDelay',\n // inbound video,\n videoRecvCodec = 'videoRecvCodec',\n videoFirCountSent = 'videoFirCountSent',\n videoPliCountSent = 'videoPliCountSent',\n videoDecodeLatency = 'videoDecodeLatency',\n videoFramesDecoded = 'videoFramesDecoded',\n videoFramesDropped = 'videoFramesDropped',\n videoRecvFrames = 'videoRecvFrames',\n videoRecvFps = 'videoRecvFps',\n videoRecvAvgJitterBufferDelay = 'videoRecvAvgJitterBufferDelay',\n videoRecvBitrates = 'videoRecvBitrates',\n videoRecvBytes = 'videoRecvBytes',\n videoRecvHeight = 'videoRecvHeight',\n videoRecvJitter = 'videoRecvJitter',\n videoRecvRoundTripTime = 'videoRecvRoundTripTime',\n videoRecvPackets = 'videoRecvPackets',\n videoRecvLostPackets = 'videoRecvLostPackets',\n videoRecvPacketsLost = 'videoRecvPacketsLost', // TODO: remove this.\n videoRecvPacketsLossRate = 'videoRecvPacketsLossRate',\n videoRecvRetransmittedPackets = 'videoRecvRetransmittedPackets',\n videoRecvNackCountSent = 'videoRecvNackCountSent',\n videoRecvWidth = 'videoRecvWidth',\n videoRecvFrameRate = 'videoRecvFrameRate',\n //'videoTotalDecodeTime',\n videoTotalFreezesDuration = 'videoTotalFreezesDuration',\n videoRecvEndToEndDelay = 'videoRecvEndToEndDelay',\n // inbound screen,\n screenRecvCodec = 'screenRecvCodec',\n screenFirCountSent = 'screenFirCountSent',\n screenPliCountSent = 'screenPliCountSent',\n screenDecodeLatency = 'screenDecodeLatency',\n screenFramesDecoded = 'screenFramesDecoded',\n screenFramesDropped = 'screenFramesDropped',\n screenRecvFrames = 'screenRecvFrames',\n screenRecvFps = 'screenRecvFps',\n screenRecvAvgJitterBufferDelay = 'screenRecvAvgJitterBufferDelay',\n screenRecvBitrates = 'screenRecvBitrates',\n screenRecvBytes = 'screenRecvBytes',\n screenRecvHeight = 'screenRecvHeight',\n screenRecvJitter = 'screenRecvJitter',\n screenRecvRoundTripTime = 'screenRecvRoundTripTime',\n screenRecvPackets = 'screenRecvPackets',\n screenRecvLostPackets = 'screenRecvLostPackets',\n screenRecvPacketsLost = 'screenRecvPacketsLost', // TODO: remove this.\n screenRecvPacketsLossRate = 'screenRecvPacketsLossRate',\n screenRecvRetransmittedPackets = 'screenRecvRetransmittedPackets',\n screenRecvNackCountSent = 'screenRecvNackCountSent',\n screenRecvWidth = 'screenRecvWidth',\n screenRecvFrameRate = 'screenRecvFrameRate',\n //'screenTotalDecodeTime',\n screenTotalFreezesDuration = 'screenTotalFreezesDuration',\n screenRecvEndToEndDelay = 'screenRecvEndToEndDelay',\n /** The transport availableOutgoingBitrate stat. */\n transportSentAvailableOutgoingBitrate = 'transportSentAvailableOutgoingBitrate',\n}\n\n/**\n * The RTC stats collection indexed by {@link RtcStatsMetricNames}.\n *\n * Each {@link RtcStatsMetricNames} record points to an object indexed by\n * `trackId:hostName:codec`, where:\n * - `trackId`: The RTC getStats track identifier.\n * - `hostName`: The remote endpoint IP address or hostname.\n * - `codec`: The track codec.\n */\nexport type RtcStats = Record<RtcStatsMetricNames, Record<string, number | string>>\n\nconst RtcStatsMetrics = Object.keys(RtcStatsMetricNames)\n\nfunction setStats(stats: RtcStats, name: RtcStatsMetricNames, key: string, value?: number | string): void {\n assert(RtcStatsMetrics.includes(name), `Unknown stat name: ${name}`)\n if (value === undefined) return\n if (!stats[name]) {\n stats[name] = {}\n }\n stats[name][key] = value\n}\n\nexport function rtcStatKey({\n pageIndex,\n trackId,\n hostName,\n codec,\n participantName,\n}: {\n pageIndex?: number\n trackId?: string\n hostName?: string\n codec?: string\n participantName?: string\n}): string {\n return [pageIndex ?? '', participantName || '', hostName || 'unknown', codec || '', trackId || ''].join(':')\n}\n\nexport function parseRtStatKey(key: string): {\n pageIndex?: number\n trackId?: string\n hostName: string\n codec?: string\n participantName?: string\n} {\n const [pageIndex, participantName, hostName, codec, trackId] = key.split(':', 5)\n return {\n pageIndex: pageIndex ? parseInt(pageIndex) : undefined,\n trackId: trackId || undefined,\n hostName: hostName || 'unknown',\n codec: codec || undefined,\n participantName: participantName || undefined,\n }\n}\n\n/**\n * Updates the {@link RtcStats} object with the collected track values.\n */\nexport function updateRtcStats(\n stats: RtcStats,\n pageIndex: number,\n trackId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any,\n signalingHost?: string,\n participantName?: string,\n): void {\n const {\n enabled,\n inboundRtp,\n outboundRtp,\n remoteAddress,\n videoSentActiveEncodings,\n sentMaxBitrate,\n isDisplay,\n codec,\n availableOutgoingBitrate,\n } = value\n const hostName = signalingHost || remoteAddress\n const key = rtcStatKey({\n pageIndex,\n trackId,\n hostName,\n codec,\n participantName,\n })\n //log.log(`updateRtcStats`, {enabled, signalingHost, remoteAddress, isDisplay, key})\n // inbound\n if (inboundRtp) {\n const prefix = inboundRtp.kind === 'video' ? (isDisplay ? 'screen' : 'video') : 'audio'\n setStats(stats, (prefix + 'RecvCodec') as RtcStatsMetricNames, key, codec)\n if (enabled) {\n setStats(stats, (prefix + 'RecvAvgJitterBufferDelay') as RtcStatsMetricNames, key, inboundRtp.jitterBuffer)\n setStats(stats, (prefix + 'RecvBitrates') as RtcStatsMetricNames, key, inboundRtp.bitrate)\n setStats(stats, (prefix + 'RecvBytes') as RtcStatsMetricNames, key, inboundRtp.bytesReceived)\n setStats(stats, (prefix + 'RecvJitter') as RtcStatsMetricNames, key, inboundRtp.jitter)\n setStats(stats, (prefix + 'RecvRoundTripTime') as RtcStatsMetricNames, key, inboundRtp.transportRoundTripTime)\n setStats(stats, (prefix + 'RecvPackets') as RtcStatsMetricNames, key, inboundRtp.packetsReceived)\n setStats(\n stats,\n (prefix + 'RecvRetransmittedPackets') as RtcStatsMetricNames,\n key,\n inboundRtp.retransmittedPacketsReceived,\n )\n // TODO: remove this.\n setStats(stats, (prefix + 'RecvPacketsLost') as RtcStatsMetricNames, key, inboundRtp.packetsLossRate)\n setStats(stats, (prefix + 'RecvPacketsLossRate') as RtcStatsMetricNames, key, inboundRtp.packetsLossRate)\n setStats(stats, (prefix + 'RecvLostPackets') as RtcStatsMetricNames, key, inboundRtp.packetsLost)\n setStats(stats, (prefix + 'RecvNackCountSent') as RtcStatsMetricNames, key, inboundRtp.nackCount)\n setStats(stats, (prefix + 'RecvEndToEndDelay') as RtcStatsMetricNames, key, inboundRtp.endToEndDelay)\n if (inboundRtp.kind === 'audio') {\n ;[\n 'audioLevel',\n 'totalSamplesReceived',\n 'concealedSamples',\n 'concealmentEvents',\n 'insertedSamplesForDeceleration',\n 'removedSamplesForAcceleration',\n ].forEach(name => {\n setStats(\n stats,\n (prefix + 'Recv' + toTitleCase(name.replace('audio', ''))) as RtcStatsMetricNames,\n key,\n inboundRtp[name],\n )\n })\n }\n if (inboundRtp.kind === 'video' && inboundRtp.keyFramesDecoded > 0) {\n setStats(stats, (prefix + 'FramesDecoded') as RtcStatsMetricNames, key, inboundRtp.framesDecoded)\n setStats(stats, (prefix + 'FramesDropped') as RtcStatsMetricNames, key, inboundRtp.framesDropped)\n setStats(stats, (prefix + 'RecvFrames') as RtcStatsMetricNames, key, inboundRtp.framesReceived)\n setStats(stats, (prefix + 'RecvFps') as RtcStatsMetricNames, key, inboundRtp.framesPerSecond)\n setStats(stats, (prefix + 'RecvHeight') as RtcStatsMetricNames, key, inboundRtp.frameHeight)\n setStats(stats, (prefix + 'RecvWidth') as RtcStatsMetricNames, key, inboundRtp.frameWidth)\n setStats(stats, (prefix + 'RecvFrameRate') as RtcStatsMetricNames, key, inboundRtp.frameRate)\n //setStats(stats, prefix + 'TotalDecodeTime', key, inboundRtp.totalDecodeTime)\n setStats(stats, (prefix + 'FirCountSent') as RtcStatsMetricNames, key, inboundRtp.firCount)\n setStats(stats, (prefix + 'PliCountSent') as RtcStatsMetricNames, key, inboundRtp.pliCount)\n setStats(stats, (prefix + 'DecodeLatency') as RtcStatsMetricNames, key, inboundRtp.decodeLatency)\n setStats(stats, (prefix + 'TotalFreezesDuration') as RtcStatsMetricNames, key, inboundRtp.totalFreezesDuration)\n }\n }\n }\n // outbound\n if (outboundRtp) {\n // log.log('outboundRtp', isDisplay, JSON.stringify(outboundRtp, null, 2));\n const prefix = outboundRtp.kind === 'video' ? (isDisplay ? 'screen' : 'video') : 'audio'\n setStats(stats, (prefix + 'SentCodec') as RtcStatsMetricNames, key, codec)\n if (enabled) {\n setStats(stats, (prefix + 'SentBitrates') as RtcStatsMetricNames, key, outboundRtp.bitrate)\n setStats(\n stats,\n (prefix + 'SentBytes') as RtcStatsMetricNames,\n key,\n outboundRtp.bytesSent + outboundRtp.headerBytesSent,\n )\n setStats(stats, (prefix + 'SentPackets') as RtcStatsMetricNames, key, outboundRtp.packetsSent)\n setStats(stats, (prefix + 'SentPacketsLost') as RtcStatsMetricNames, key, outboundRtp.packetsLossRate)\n setStats(stats, (prefix + 'SentNackCountRecv') as RtcStatsMetricNames, key, outboundRtp.nackCount)\n //setStats(stats, prefix + 'SentPacketsLostCount', key, outboundRtp.packetsLost)\n setStats(stats, (prefix + 'SentRoundTripTime') as RtcStatsMetricNames, key, outboundRtp.roundTripTime)\n setStats(stats, (prefix + 'SentJitter') as RtcStatsMetricNames, key, outboundRtp.jitter)\n setStats(\n stats,\n (prefix + 'SentTransportRoundTripTime') as RtcStatsMetricNames,\n key,\n outboundRtp.transportRoundTripTime,\n )\n setStats(stats, 'transportSentAvailableOutgoingBitrate' as RtcStatsMetricNames, key, availableOutgoingBitrate)\n setStats(stats, (prefix + 'SentMaxBitrate') as RtcStatsMetricNames, key, sentMaxBitrate)\n setStats(\n stats,\n (prefix + 'SentRetransmittedPackets') as RtcStatsMetricNames,\n key,\n outboundRtp.retransmittedPacketsSent,\n )\n if (outboundRtp.kind === 'video') {\n setStats(stats, (prefix + 'SentActiveEncodings') as RtcStatsMetricNames, key, videoSentActiveEncodings)\n setStats(\n stats,\n (prefix + 'QualityLimitationResolutionChanges') as RtcStatsMetricNames,\n key,\n outboundRtp.qualityLimitationResolutionChanges,\n )\n setStats(stats, (prefix + 'QualityLimitationCpu') as RtcStatsMetricNames, key, outboundRtp.qualityLimitationCpu)\n setStats(\n stats,\n (prefix + 'QualityLimitationBandwidth') as RtcStatsMetricNames,\n key,\n outboundRtp.qualityLimitationBandwidth,\n )\n setStats(stats, (prefix + 'SentWidth') as RtcStatsMetricNames, key, outboundRtp.frameWidth)\n setStats(stats, (prefix + 'SentHeight') as RtcStatsMetricNames, key, outboundRtp.frameHeight)\n setStats(stats, (prefix + 'SentFrames') as RtcStatsMetricNames, key, outboundRtp.framesSent)\n setStats(stats, (prefix + 'SentFps') as RtcStatsMetricNames, key, outboundRtp.framesPerSecond)\n setStats(stats, (prefix + 'FirCountReceived') as RtcStatsMetricNames, key, outboundRtp.firCountReceived)\n setStats(stats, (prefix + 'PliCountReceived') as RtcStatsMetricNames, key, outboundRtp.pliCountReceived)\n setStats(stats, (prefix + 'EncodeLatency') as RtcStatsMetricNames, key, outboundRtp.encodeLatency)\n setStats(stats, (prefix + 'SentLatency') as RtcStatsMetricNames, key, outboundRtp.sentLatency)\n }\n }\n }\n}\n"]}
@@ -31,6 +31,7 @@ declare global {
31
31
  screenStartFrameDelay: number;
32
32
  };
33
33
  collectCpuPressure: () => number;
34
+ collectQuestionAnswerDelay: () => number;
34
35
  collectVideoStats: () => {
35
36
  width: number;
36
37
  height: number;
@@ -534,15 +534,18 @@ try {
534
534
  console.error('[webrtcperf] Error parsing scriptParams:', err);
535
535
  webrtcperf.params = {};
536
536
  };
537
+
538
+ const webrtcperf_getServerUrl = (path, protocol = 'http', query = '') => {
539
+ return protocol + "${this.serverUseHttps ? 's' : ''}://localhost:${this.serverPort}/" + path + "?auth=${this.serverSecret}" + (query ? "&" + query : '')
540
+ }
537
541
  `;
538
542
  if (this.serverPort) {
539
543
  cmd += `\
540
- webrtcperf.config.SAVE_MEDIA_URL = "ws${this.serverUseHttps ? 's' : ''}://localhost:${this.serverPort}/?auth=${this.serverSecret}&action=write-stream";
544
+ webrtcperf.config.SAVE_MEDIA_URL = webrtcperf_getServerUrl("", "ws", "action=write-stream");
541
545
  `;
542
546
  if (this.mediaPath?.mp4 && !this.useFakeMedia) {
543
547
  cmd += `\
544
- webrtcperf.config.VIDEO_URL = "http${this.serverUseHttps ? 's' : ''}://localhost:${this.serverPort}/cache/${path_1.default.basename(this.mediaPath.mp4)}?auth=${this.serverSecret}";
545
- webrtcperf.config.AUDIO_URL = "http${this.serverUseHttps ? 's' : ''}://localhost:${this.serverPort}/cache/${path_1.default.basename(this.mediaPath.m4a)}?auth=${this.serverSecret}";
548
+ webrtcperf.config.MEDIA_URL = webrtcperf_getServerUrl("cache/${path_1.default.basename(this.mediaPath.mp4)}");
546
549
  `;
547
550
  }
548
551
  }
@@ -1334,6 +1337,7 @@ mv ${logFilePath}.tmp ${logFilePath};
1334
1337
  const pageCpu = {};
1335
1338
  const pageMemory = {};
1336
1339
  const cpuPressureStats = {};
1340
+ const questionAnswerDelayStats = {};
1337
1341
  const videoWidth = {};
1338
1342
  const videoHeight = {};
1339
1343
  const videoBufferedTime = {};
@@ -1352,11 +1356,12 @@ mv ${logFilePath}.tmp ${logFilePath};
1352
1356
  await Promise.allSettled([...this.pages.entries()].map(async ([pageIndex, page]) => {
1353
1357
  try {
1354
1358
  // Collect stats from the page.
1355
- const { peerConnectionStats, audioEndToEndDelay, videoEndToEndDelay, cpuPressure, videoStats, customMetrics, } = await page.evaluate(async () => ({
1359
+ const { peerConnectionStats, audioEndToEndDelay, videoEndToEndDelay, cpuPressure, questionAnswerDelay, videoStats, customMetrics, } = await page.evaluate(async () => ({
1356
1360
  peerConnectionStats: await webrtcperf.collectPeerConnectionStats(),
1357
1361
  audioEndToEndDelay: webrtcperf.collectAudioEndToEndStats(),
1358
1362
  videoEndToEndDelay: webrtcperf.collectVideoEndToEndStats(),
1359
1363
  cpuPressure: webrtcperf.collectCpuPressure(),
1364
+ questionAnswerDelay: webrtcperf.collectQuestionAnswerDelay(),
1360
1365
  videoStats: webrtcperf.collectVideoStats(),
1361
1366
  customMetrics: 'collectCustomMetrics' in window ? collectCustomMetrics() : null,
1362
1367
  }));
@@ -1420,6 +1425,8 @@ mv ${logFilePath}.tmp ${logFilePath};
1420
1425
  }
1421
1426
  if (cpuPressure !== undefined)
1422
1427
  cpuPressureStats[pageKey] = cpuPressure;
1428
+ if (questionAnswerDelay !== undefined)
1429
+ questionAnswerDelayStats[pageKey] = questionAnswerDelay;
1423
1430
  if (videoStats) {
1424
1431
  videoWidth[pageKey] = videoStats.width;
1425
1432
  videoHeight[pageKey] = videoStats.height;
@@ -1517,6 +1524,7 @@ mv ${logFilePath}.tmp ${logFilePath};
1517
1524
  wsRecvBytes: wsRecvBytesStats,
1518
1525
  wsRecvLatency: wsRecvLatencyStats,
1519
1526
  cpuPressure: cpuPressureStats,
1527
+ questionAnswerDelay: questionAnswerDelayStats,
1520
1528
  videoWidth,
1521
1529
  videoHeight,
1522
1530
  videoBufferedTime,