@rtcstats/rtcstats-js 2.3.0 → 2.5.0

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.
package/README.md CHANGED
@@ -9,6 +9,26 @@ an Experience Score, and a plain-English AI summary of what went wrong on the ca
9
9
  For a complete reference of every getStats() metric rtcstats collects and analyzes, see
10
10
  the [WebRTC Stats Reference](https://rtcstats.com/kb/webrtc-stats-reference-page).
11
11
 
12
+ ## Why rtcStats is built this way
13
+
14
+ rtcStats keeps collecting session data, storing it, and analyzing it separate. The
15
+ first two are open source and run in your stack. The third is optional and yours to
16
+ trigger.
17
+
18
+ - **Collection is a client SDK you control.** `rtcstats-js` runs in your client and
19
+ streams a dump of what WebRTC is doing to a server you run.
20
+ - **Storage runs on your infrastructure.** `rtcstats-server` receives the stream and
21
+ writes each dump to your own storage. Session data lands and lives in your stack.
22
+ - **Analysis is the layer you opt into.** You choose which stored dumps to send to
23
+ rtcstats.com: a random sample, per-user, per-region, a single dump when one call
24
+ goes bad, or none at all. rtcstats.com returns Observations, an Experience Score,
25
+ and a plain-English summary of what went wrong. It is the layer above
26
+ `webrtc-internals`, not a replacement for it.
27
+
28
+ Send what you want, keep the rest.
29
+
30
+ Start at https://rtcstats.com
31
+
12
32
  # rtcstats-js: A Javascript client SDK for monitoring WebRTC
13
33
 
14
34
  The Javascript SDK provides low-level logging on peerconnection API calls and periodic getStats calls for analytics/debugging purposes.
@@ -28,6 +48,7 @@ The main rtcstats.js exports a number of methods that facilitate this:
28
48
  object and generates traces using the supplied `trace` method.
29
49
  * `wrapGetUserMedia` and `wrapEnumerateDevices` do the same for the `getUserMedia`/`getDisplayMedia`,
30
50
  `enumerateDevices` and related APIs such as MediaStreamTracks and HTMLVideoElement.
51
+ * `wrapSetSinkId` does the same for HTMLMediaElement's `setSinkId` method which changes the audio output device.
31
52
 
32
53
  Typical usage looks like this:
33
54
  ```
package/media.js CHANGED
@@ -132,3 +132,30 @@ export function wrapEnumerateDevices(trace, {navigator}) {
132
132
  }
133
133
  }
134
134
 
135
+ /**
136
+ * Wraps HTMLMediaElement.setSinkId for RTCStats.
137
+ *
138
+ * @param {function} trace - RTCStats trace callback.
139
+ * @param {object} window - window object with HTMLMediaElement.
140
+ */
141
+ export function wrapSetSinkId(trace, {HTMLMediaElement}) {
142
+ if (!(HTMLMediaElement && HTMLMediaElement.prototype.setSinkId)) {
143
+ return;
144
+ }
145
+ if (HTMLMediaElement.prototype.setSinkId.__rtcStats) {
146
+ // Prevent double-wrapping.
147
+ return;
148
+ }
149
+ const origMethod = HTMLMediaElement.prototype.setSinkId;
150
+ const wrappedMethod = function(...args) {
151
+ trace('HTMLMediaElement.setSinkId', null, args[0]);
152
+ return origMethod.apply(this, args)
153
+ .then((result) => result, (err) => {
154
+ trace('HTMLMediaElement.setSinkIdOnFailure', null, err.toString(), args[0]);
155
+ return Promise.reject(err);
156
+ });
157
+ };
158
+ wrappedMethod.__rtcStats = true;
159
+ HTMLMediaElement.prototype.setSinkId = wrappedMethod;
160
+ }
161
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtcstats/rtcstats-js",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "gather WebRTC API traces and statistics",
5
5
  "main": "rtcstats.js",
6
6
  "type": "module",
package/peerconnection.js CHANGED
@@ -92,8 +92,7 @@ export function wrapRTCPeerConnection(trace, window, {getStatsInterval}) {
92
92
  let lastComputePressureRecord;
93
93
  if (window.PressureObserver && getStatsInterval) {
94
94
  const observer = new window.PressureObserver((records) => {
95
- const lastRecord = records[records.length - 1]; // Usually only one record.
96
- lastComputePressureRecord = [Date.now(), lastRecord];
95
+ lastComputePressureRecord = records[records.length - 1]; // Usually only one record.
97
96
  });
98
97
  observer.observe('cpu', {sampleInterval: getStatsInterval});
99
98
  }
@@ -148,11 +147,6 @@ export function wrapRTCPeerConnection(trace, window, {getStatsInterval}) {
148
147
  e.track.addEventListener('mute', () => {
149
148
  trace('MediaStreamTrack.onmute', pcId, e.track.id);
150
149
  });
151
- if (e.transceiver) {
152
- e.transceiver.__rtcStatsId = pcId;
153
- e.transceiver.sender.__rtcStatsId = pcId;
154
- e.transceiver.sender.__rtcStatsSenderId = e.track.id;
155
- }
156
150
  if (e.track.kind === 'video' && window.document?.querySelectorAll) {
157
151
  setTimeout(() => {
158
152
  window.document.querySelectorAll('video').forEach(el => {
@@ -199,10 +193,10 @@ export function wrapRTCPeerConnection(trace, window, {getStatsInterval}) {
199
193
  return;
200
194
  }
201
195
  if (lastComputePressureRecord) {
202
- const [timestamp, record] = lastComputePressureRecord;
196
+ const record = lastComputePressureRecord;
203
197
  stats['rtcStatsComputePressure'] = {
204
198
  type: 'compute-pressure',
205
- timestamp,
199
+ timestamp: window.performance.timeOrigin + record.time,
206
200
  cpuState: computePressureTable[record.state] || record.state,
207
201
  };
208
202
  }
@@ -376,6 +370,11 @@ export function wrapRTCPeerConnection(trace, window, {getStatsInterval}) {
376
370
 
377
371
  return nativeMethod.apply(this, [description, ...args])
378
372
  .then(() => {
373
+ this.getTransceivers().forEach((transceiver) => {
374
+ transceiver.__rtcStatsId = this.__rtcStatsId;
375
+ transceiver.sender.__rtcStatsId = this.__rtcStatsId;
376
+ transceiver.sender.__rtcStatsSenderId = transceiver.receiver.track.id;
377
+ });
379
378
  trace(method + 'OnSuccess', this.__rtcStatsId, undefined,
380
379
  trackingId);
381
380
  }, (err) => {
package/rtcstats.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import {wrapRTCPeerConnection} from './peerconnection.js';
2
- import {wrapGetUserMedia, wrapEnumerateDevices} from './media.js';
2
+ import {wrapGetUserMedia, wrapEnumerateDevices, wrapSetSinkId} from './media.js';
3
3
  import {WebSocketTrace} from './trace-websocket.js';
4
4
 
5
5
  /**
@@ -16,6 +16,8 @@ export function wrapRTCStatsWithDefaultOptions(config = {getStatsInterval: 1000}
16
16
  wrapGetUserMedia(trace, target);
17
17
  // Wrap enumerateDevices.
18
18
  wrapEnumerateDevices(trace, target);
19
+ // Wrap HTMLMediaElement.setSinkId.
20
+ wrapSetSinkId(trace, target);
19
21
 
20
22
  return trace;
21
23
  }
@@ -24,5 +26,6 @@ export {
24
26
  wrapRTCPeerConnection,
25
27
  wrapGetUserMedia,
26
28
  wrapEnumerateDevices,
29
+ wrapSetSinkId,
27
30
  WebSocketTrace,
28
31
  };
@@ -44,7 +44,6 @@ export function WebSocketTrace(config = {}) {
44
44
  buffer.push(args);
45
45
  }
46
46
  };
47
-
48
47
  trace.close = () => {
49
48
  if (window.sessionStorage && config.countReloads) {
50
49
  // A clean disconnect clears the reload count.
@@ -67,6 +66,7 @@ export function WebSocketTrace(config = {}) {
67
66
  hardwareConcurrency: navigator.hardwareConcurrency,
68
67
  userAgentData: navigator.userAgentData,
69
68
  deviceMemory: navigator.deviceMemory,
69
+ cpuPerformance: navigator.cpuPerformance,
70
70
  screen: {
71
71
  width: window.screen?.availWidth,
72
72
  height: window.screen?.availHeight,