@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 +21 -0
- package/media.js +27 -0
- package/package.json +1 -1
- package/peerconnection.js +8 -9
- package/rtcstats.js +4 -1
- package/trace-websocket.js +1 -1
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
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
|
-
|
|
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
|
|
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
|
};
|
package/trace-websocket.js
CHANGED
|
@@ -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,
|