@observertc/client-monitor-js 3.3.1 → 3.4.1-e6caa47.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 +62 -71
- package/lib/ClientMonitor.d.ts +27 -10
- package/lib/ClientMonitor.d.ts.map +1 -1
- package/lib/ClientMonitor.js +75 -24
- package/lib/entries/PeerConnectionEntryManifest.js +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +6 -6
- package/package.json +1 -1
- package/lib/utils/Timer.d.ts +0 -15
- package/lib/utils/Timer.d.ts.map +0 -1
- package/lib/utils/Timer.js +0 -100
package/README.md
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
Javascript library to monitor WebRTC applications
|
|
2
|
-
---
|
|
1
|
+
## Javascript library to monitor WebRTC applications
|
|
3
2
|
|
|
4
3
|
@observertc/client-monitor-js is a client side library to monitor [WebRTCStats](https://www.w3.org/TR/webrtc-stats/) and to integrate your app to observertc components.
|
|
5
4
|
|
|
6
5
|
Table of Contents:
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
- [Quick Start](#quick-start)
|
|
8
|
+
- [Integrations](#integrations)
|
|
9
|
+
- [Mediasoup](#mediasoup)
|
|
10
|
+
- [Detectors and Alerts](#detectors-and-alerts)
|
|
11
|
+
- [Audio Desync Detector](#audio-desync-detector)
|
|
12
|
+
- [CPU Performance Detector](#cpu-performance-detector)
|
|
13
|
+
- [Calculated updates](#calculated-updates)
|
|
14
|
+
- [Configurations](#configurations)
|
|
15
|
+
- [NPM package](#npm-package)
|
|
16
|
+
- [API docs](#api-docs)
|
|
17
|
+
- [Schemas](#schemas)
|
|
18
|
+
- [Getting Involved](#getting-involved)
|
|
19
|
+
- [License](#license)
|
|
21
20
|
|
|
22
21
|
## Qucik Start
|
|
23
22
|
|
|
@@ -38,7 +37,7 @@ const config = {
|
|
|
38
37
|
const monitor = createClientMonitor(config);
|
|
39
38
|
const statsCollector = monitor.collectors.collectFromRTCPeerConnection(peerConnection);
|
|
40
39
|
|
|
41
|
-
monitor.on(
|
|
40
|
+
monitor.on("stats-collected", () => {
|
|
42
41
|
const storage = monitor.storage;
|
|
43
42
|
for (const inboundRtp of storage.inboundRtps()) {
|
|
44
43
|
const trackId = inboundRtp.getTrackId();
|
|
@@ -51,11 +50,11 @@ statsCollector.close();
|
|
|
51
50
|
```
|
|
52
51
|
|
|
53
52
|
The above example do as follows:
|
|
54
|
-
1. create a client monitor, which collect stats every 5s
|
|
55
|
-
2. setup a stats collector from a peer connection
|
|
56
|
-
3. register an event called after stats are collected
|
|
57
|
-
4. print out the inbound rtps and then close the stats collector we registered in step 3.
|
|
58
53
|
|
|
54
|
+
1. create a client monitor, which collect stats every 5s
|
|
55
|
+
2. setup a stats collector from a peer connection
|
|
56
|
+
3. register an event called after stats are collected
|
|
57
|
+
4. print out the inbound rtps and then close the stats collector we registered in step 3.
|
|
59
58
|
|
|
60
59
|
## Integrations
|
|
61
60
|
|
|
@@ -72,29 +71,28 @@ const config = {
|
|
|
72
71
|
const monitor = createClientMonitor(config);
|
|
73
72
|
const mediasoupStatsCollector = monitor.collectors.collectFromMediasoupDevice(mediasoupDevice);
|
|
74
73
|
|
|
75
|
-
monitor.on(
|
|
74
|
+
monitor.on("stats-collected", () => {
|
|
76
75
|
// do your stuff
|
|
77
76
|
|
|
78
|
-
// you can close detach mediasoup
|
|
77
|
+
// you can close detach mediasoup
|
|
79
78
|
// collector by calling the close
|
|
80
79
|
mediasoupStatsCollector.close();
|
|
81
|
-
})
|
|
80
|
+
});
|
|
82
81
|
```
|
|
83
82
|
|
|
84
|
-
**Important Note**: The created collector is hooked on the device 'newtransport' event,
|
|
83
|
+
**Important Note**: The created collector is hooked on the device 'newtransport' event,
|
|
85
84
|
and can detect transports automatically when they are created after the device is added.
|
|
86
85
|
If you create transports before you add the device to the monitor,
|
|
87
|
-
transports you created before will not be monitored automatically, you need to add them
|
|
86
|
+
transports you created before will not be monitored automatically, you need to add them
|
|
88
87
|
to the statscollector, like this:
|
|
89
88
|
|
|
90
89
|
```javascript
|
|
91
|
-
const myTransport = // your transport created before the device is added to the monitor
|
|
92
|
-
mediasoupStatsCollector.addTransport(myTransport)
|
|
90
|
+
const myTransport = mediasoupStatsCollector.addTransport(myTransport); // your transport created before the device is added to the monitor
|
|
93
91
|
```
|
|
94
92
|
|
|
95
93
|
## Calculated Updates
|
|
96
94
|
|
|
97
|
-
The Calculated Updates lets you observer metrics derived from the polled webrtc stats
|
|
95
|
+
The Calculated Updates lets you observer metrics derived from the polled webrtc stats captured by the library. These calculated updates provide a richer, more nuanced understanding of your application's client-side behavior, offering valuable insights beyond what raw stats metrics can give you.
|
|
98
96
|
|
|
99
97
|
### Storage Updates
|
|
100
98
|
|
|
@@ -119,7 +117,7 @@ monitor.on('stats-collected', () => {
|
|
|
119
117
|
### PeerConnection Updates
|
|
120
118
|
|
|
121
119
|
```javascript
|
|
122
|
-
import { createClientMonitor } from
|
|
120
|
+
import { createClientMonitor } from "client-monitor-js";
|
|
123
121
|
|
|
124
122
|
// Create a ClientMonitor instance
|
|
125
123
|
const monitor = createClientMonitor({
|
|
@@ -127,22 +125,21 @@ const monitor = createClientMonitor({
|
|
|
127
125
|
});
|
|
128
126
|
|
|
129
127
|
const storage = monitor.storage;
|
|
130
|
-
monitor.on(
|
|
128
|
+
monitor.on("stats-collected", () => {
|
|
131
129
|
for (const peerConnection of storage.peerConnections()) {
|
|
132
|
-
console.log(
|
|
133
|
-
console.log(
|
|
134
|
-
console.log(
|
|
135
|
-
console.log(
|
|
136
|
-
console.log(
|
|
130
|
+
console.log("average RTT in seconds", peerConnection.avgRttInS);
|
|
131
|
+
console.log("Sending audio bitrate on PC", peerConnection.sendingAudioBitrate);
|
|
132
|
+
console.log("Sending video bitrate on PC", peerConnection.sendingVideoBitrate);
|
|
133
|
+
console.log("Receiving audio bitrate on PC", peerConnection.receivingAudioBitrate);
|
|
134
|
+
console.log("Receiving video bitrate on PC", peerConnection.receivingVideoBitrate);
|
|
137
135
|
}
|
|
138
136
|
});
|
|
139
|
-
|
|
140
137
|
```
|
|
141
138
|
|
|
142
139
|
### Inbound RTP stats updates
|
|
143
140
|
|
|
144
141
|
```javascript
|
|
145
|
-
import { createClientMonitor } from
|
|
142
|
+
import { createClientMonitor } from "client-monitor-js";
|
|
146
143
|
|
|
147
144
|
// Create a ClientMonitor instance
|
|
148
145
|
const monitor = createClientMonitor({
|
|
@@ -150,24 +147,22 @@ const monitor = createClientMonitor({
|
|
|
150
147
|
});
|
|
151
148
|
|
|
152
149
|
const storage = monitor.storage;
|
|
153
|
-
monitor.on(
|
|
150
|
+
monitor.on("stats-collected", () => {
|
|
154
151
|
for (const inboundRtp of storage.inboundRtps()) {
|
|
152
|
+
console.log("mean opinion score for inbound-rtp", inboundRtp.score);
|
|
155
153
|
|
|
156
|
-
console.log(
|
|
157
|
-
|
|
158
|
-
console.log(
|
|
159
|
-
console.log(
|
|
160
|
-
console.log('received packets since last stats-collected', inboundRtp.receivedPackets);
|
|
161
|
-
console.log('decoded frames since last stats-collected', inboundRtp.decodedFrames);
|
|
154
|
+
console.log("receiving bitrate", inboundRtp.receivingBitrate);
|
|
155
|
+
console.log("lost packets since last stats-collected", inboundRtp.lostPackets);
|
|
156
|
+
console.log("received packets since last stats-collected", inboundRtp.receivedPackets);
|
|
157
|
+
console.log("decoded frames since last stats-collected", inboundRtp.decodedFrames);
|
|
162
158
|
}
|
|
163
159
|
});
|
|
164
|
-
|
|
165
160
|
```
|
|
166
161
|
|
|
167
162
|
### Outbound RTP stats updates
|
|
168
163
|
|
|
169
164
|
```javascript
|
|
170
|
-
import { createClientMonitor } from
|
|
165
|
+
import { createClientMonitor } from "client-monitor-js";
|
|
171
166
|
|
|
172
167
|
// Create a ClientMonitor instance
|
|
173
168
|
const monitor = createClientMonitor({
|
|
@@ -175,19 +170,20 @@ const monitor = createClientMonitor({
|
|
|
175
170
|
});
|
|
176
171
|
|
|
177
172
|
const storage = monitor.storage;
|
|
178
|
-
monitor.on(
|
|
173
|
+
monitor.on("stats-collected", () => {
|
|
179
174
|
for (const outboundRtp of storage.outboundRtps()) {
|
|
175
|
+
console.log("stability score outbound-rtp", outboundRtp.score);
|
|
180
176
|
|
|
181
|
-
console.log(
|
|
177
|
+
console.log("sending bitrate", outboundRtp.sendingBitrate);
|
|
178
|
+
console.log("sent packets since last stats-collected", outboundRtp.sentPackets);
|
|
182
179
|
|
|
183
|
-
console.log('sending bitrate', outboundRtp.sendingBitrate);
|
|
184
|
-
console.log('sent packets since last stats-collected', outboundRtp.sentPackets);
|
|
185
|
-
|
|
186
180
|
const remoteInboundRtp = outboundRtp.getRemoteInboundRtp();
|
|
187
|
-
console.log(
|
|
181
|
+
console.log(
|
|
182
|
+
"Received packets on remote inbound-rtp belongs to this outbound-rtp",
|
|
183
|
+
remoteInboundRtp?.receivedPackets
|
|
184
|
+
);
|
|
188
185
|
}
|
|
189
186
|
});
|
|
190
|
-
|
|
191
187
|
```
|
|
192
188
|
|
|
193
189
|
## Detectors and Alerts
|
|
@@ -195,8 +191,9 @@ monitor.on('stats-collected', () => {
|
|
|
195
191
|
Detectors and alerts provide events of tracking and responding to anomalies or performance issues based on the polled stats. Detectors are components that continuously monitor for specific conditions in the polled stats, and set an alert if certain thresholds are hit. You can subscribe to alerts of an instantiated client-monitor-js and configure detectors via initial configurations.
|
|
196
192
|
|
|
197
193
|
List of built-in alerts:
|
|
198
|
-
|
|
199
|
-
|
|
194
|
+
|
|
195
|
+
- `audio-desync-alert`: triggered when for an audio track several acceleration and deceleration is detected in a short amount of time indicating that the controlling system tries compensate discrepancies.
|
|
196
|
+
- `cpu-performance-alert`: triggered whenever a browser detects quality limitation becasue of CPU, or the number of decoded frames per sec hit a certain threshold
|
|
200
197
|
|
|
201
198
|
### Audio Desync Detector
|
|
202
199
|
|
|
@@ -275,24 +272,19 @@ const config = {
|
|
|
275
272
|
/**
|
|
276
273
|
* By setting it, the monitor calls the added statsCollectors periodically
|
|
277
274
|
* and pulls the stats.
|
|
278
|
-
*
|
|
279
|
-
* DEFAULT:
|
|
275
|
+
*
|
|
276
|
+
* DEFAULT: 5000
|
|
280
277
|
*/
|
|
281
278
|
collectingPeriodInMs: 5000,
|
|
282
|
-
/**
|
|
283
|
-
* By setting it, the monitor make samples periodically.
|
|
284
|
-
*
|
|
285
|
-
* DEFAULT: undefined
|
|
286
|
-
*/
|
|
287
|
-
samplingPeriodInMs: 10000,
|
|
288
279
|
|
|
289
280
|
/**
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
281
|
+
* By setting this, the observer makes samples after n number or collected stats.
|
|
282
|
+
*
|
|
283
|
+
* For example if the value is 10, the observer makes a sample after 10 collected stats (in every 10 collectingPeriodInMs).
|
|
284
|
+
*
|
|
285
|
+
* DEFAULT: 1
|
|
294
286
|
*/
|
|
295
|
-
|
|
287
|
+
samplingTick: 1,
|
|
296
288
|
};
|
|
297
289
|
```
|
|
298
290
|
|
|
@@ -308,11 +300,10 @@ https://observertc.org/docs/api/client-monitor-js-v2/
|
|
|
308
300
|
|
|
309
301
|
https://github.com/observertc/schemas
|
|
310
302
|
|
|
311
|
-
|
|
312
303
|
## Getting Involved
|
|
313
304
|
|
|
314
|
-
Client-monitor is made with the intention to provide an open-source monitoring solution for
|
|
315
|
-
WebRTC developers. If you are interested in getting involved
|
|
305
|
+
Client-monitor is made with the intention to provide an open-source monitoring solution for
|
|
306
|
+
WebRTC developers. If you are interested in getting involved
|
|
316
307
|
please read our [contribution](CONTRIBUTING.md) guideline.
|
|
317
308
|
|
|
318
309
|
## License
|
package/lib/ClientMonitor.d.ts
CHANGED
|
@@ -16,17 +16,13 @@ export type ClientMonitorConfig = {
|
|
|
16
16
|
*/
|
|
17
17
|
collectingPeriodInMs?: number;
|
|
18
18
|
/**
|
|
19
|
-
* By setting this, the observer makes samples
|
|
19
|
+
* By setting this, the observer makes samples after n number or collected stats.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
23
|
-
samplingPeriodInMs?: number;
|
|
24
|
-
/**
|
|
25
|
-
* Sets the ticking time of the timer that invokes processes for collecting, sampling, and sending.
|
|
21
|
+
* For example if the value is 10, the observer makes a sample after 10 collected stats (in every 10 collectingPeriodInMs).
|
|
26
22
|
*
|
|
27
|
-
* DEFAULT:
|
|
23
|
+
* DEFAULT: undefined
|
|
28
24
|
*/
|
|
29
|
-
|
|
25
|
+
samplingTick?: number;
|
|
30
26
|
};
|
|
31
27
|
export type AlertState = 'on' | 'off';
|
|
32
28
|
export interface ClientMonitorEvents {
|
|
@@ -101,10 +97,11 @@ export declare class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents
|
|
|
101
97
|
};
|
|
102
98
|
private readonly _detectors;
|
|
103
99
|
private readonly _sampler;
|
|
104
|
-
private
|
|
100
|
+
private _timer?;
|
|
105
101
|
private _lastCollectedAt;
|
|
106
102
|
private _lastSampledAt;
|
|
107
103
|
private _closed;
|
|
104
|
+
private _actualCollectingTick;
|
|
108
105
|
constructor(_config: ClientMonitorConfig);
|
|
109
106
|
get closed(): boolean;
|
|
110
107
|
close(): void;
|
|
@@ -118,7 +115,7 @@ export declare class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents
|
|
|
118
115
|
addCustomCallEvent(event: CustomCallEvent): void;
|
|
119
116
|
addLocalSDP(localSDP: string[]): void;
|
|
120
117
|
setCollectingPeriod(collectingPeriodInMs: number): void;
|
|
121
|
-
|
|
118
|
+
setSamplingTick(samplingTick: number): void;
|
|
122
119
|
get audioDesyncDetector(): {
|
|
123
120
|
id: string;
|
|
124
121
|
update: () => Promise<void>;
|
|
@@ -132,6 +129,26 @@ export declare class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents
|
|
|
132
129
|
addCongestionDetector(config?: CongestionDetectorConfig): void;
|
|
133
130
|
getTrackStats(trackId: string): TrackStats | undefined;
|
|
134
131
|
getPeerConnectionStats(peerConnectionId: string): PeerConnectionEntry | undefined;
|
|
132
|
+
get codecs(): import("./entries/StatsEntryInterfaces").CodecEntry[];
|
|
133
|
+
get inboundRtps(): import("./entries/StatsEntryInterfaces").InboundRtpEntry[];
|
|
134
|
+
get outboundRtps(): import("./entries/StatsEntryInterfaces").OutboundRtpEntry[];
|
|
135
|
+
get remoteInboundRtps(): import("./entries/StatsEntryInterfaces").RemoteInboundRtpEntry[];
|
|
136
|
+
get remoteOutboundRtps(): import("./entries/StatsEntryInterfaces").RemoteOutboundRtpEntry[];
|
|
137
|
+
get mediaSources(): import("./entries/StatsEntryInterfaces").MediaSourceEntry[];
|
|
138
|
+
get contributingSources(): import("./entries/StatsEntryInterfaces").ContributingSourceEntry[];
|
|
139
|
+
get dataChannels(): import("./entries/StatsEntryInterfaces").DataChannelEntry[];
|
|
140
|
+
get transceivers(): import("./entries/StatsEntryInterfaces").TransceiverEntry[];
|
|
141
|
+
get senders(): import("./entries/StatsEntryInterfaces").SenderEntry[];
|
|
142
|
+
get receivers(): import("./entries/StatsEntryInterfaces").ReceiverEntry[];
|
|
143
|
+
get transports(): import("./entries/StatsEntryInterfaces").TransportEntry[];
|
|
144
|
+
get sctpTransports(): import("./entries/StatsEntryInterfaces").SctpTransportEntry[];
|
|
145
|
+
get iceCandidatePairs(): import("./entries/StatsEntryInterfaces").IceCandidatePairEntry[];
|
|
146
|
+
get iceLocalCandidates(): import("./entries/StatsEntryInterfaces").LocalCandidateEntry[];
|
|
147
|
+
get iceRemoteCandidates(): import("./entries/StatsEntryInterfaces").RemoteCandidateEntry[];
|
|
148
|
+
get certificates(): import("./entries/StatsEntryInterfaces").CertificateEntry[];
|
|
149
|
+
get iceServers(): import("./entries/StatsEntryInterfaces").IceServerEntry[];
|
|
150
|
+
get peerConnections(): PeerConnectionEntry[];
|
|
151
|
+
get tracks(): TrackStats[];
|
|
135
152
|
private _setupTimer;
|
|
136
153
|
}
|
|
137
154
|
//# sourceMappingURL=ClientMonitor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientMonitor.d.ts","sourceRoot":"","sources":["../src/ClientMonitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAoB,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"ClientMonitor.d.ts","sourceRoot":"","sources":["../src/ClientMonitor.ts"],"names":[],"mappings":"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"}
|
package/lib/ClientMonitor.js
CHANGED
|
@@ -29,7 +29,6 @@ const logger_1 = require("./utils/logger");
|
|
|
29
29
|
const ClientMetaData_1 = require("./ClientMetaData");
|
|
30
30
|
const StatsStorage_1 = require("./entries/StatsStorage");
|
|
31
31
|
const TypedEmitter_1 = require("./utils/TypedEmitter");
|
|
32
|
-
const Timer_1 = require("./utils/Timer");
|
|
33
32
|
const Sampler_1 = require("./Sampler");
|
|
34
33
|
const Adapter_1 = require("./collectors/Adapter");
|
|
35
34
|
const validators = __importStar(require("./utils/validators"));
|
|
@@ -47,10 +46,10 @@ class ClientMonitor extends TypedEmitter_1.TypedEventEmitter {
|
|
|
47
46
|
clientMonitor: this,
|
|
48
47
|
});
|
|
49
48
|
this._sampler = new Sampler_1.Sampler(this.storage);
|
|
50
|
-
this._timer = (0, Timer_1.createTimer)();
|
|
51
49
|
this._lastCollectedAt = Date.now();
|
|
52
50
|
this._lastSampledAt = 0;
|
|
53
51
|
this._closed = false;
|
|
52
|
+
this._actualCollectingTick = 0;
|
|
54
53
|
this.meta = new ClientMetaData_1.ClientMetaData();
|
|
55
54
|
this._sampler.addBrowser(this.meta.browser);
|
|
56
55
|
this._sampler.addEngine(this.meta.engine);
|
|
@@ -84,10 +83,11 @@ class ClientMonitor extends TypedEmitter_1.TypedEventEmitter {
|
|
|
84
83
|
return;
|
|
85
84
|
}
|
|
86
85
|
this._closed = true;
|
|
87
|
-
this._timer
|
|
86
|
+
clearInterval(this._timer);
|
|
88
87
|
this.storage.clear();
|
|
89
88
|
this.collectors.clear();
|
|
90
89
|
this._sampler.clear();
|
|
90
|
+
this._timer = undefined;
|
|
91
91
|
}
|
|
92
92
|
async collect() {
|
|
93
93
|
const collectedStats = await this.collectors.collect();
|
|
@@ -98,6 +98,10 @@ class ClientMonitor extends TypedEmitter_1.TypedEventEmitter {
|
|
|
98
98
|
elapsedSinceLastCollectedInMs: timestamp - this._lastCollectedAt,
|
|
99
99
|
});
|
|
100
100
|
this._lastCollectedAt = timestamp;
|
|
101
|
+
if (this._config.samplingTick && this._config.samplingTick <= ++this._actualCollectingTick) {
|
|
102
|
+
this._actualCollectingTick = 0;
|
|
103
|
+
this.sample();
|
|
104
|
+
}
|
|
101
105
|
return collectedStats;
|
|
102
106
|
}
|
|
103
107
|
sample() {
|
|
@@ -154,8 +158,8 @@ class ClientMonitor extends TypedEmitter_1.TypedEventEmitter {
|
|
|
154
158
|
this._config.collectingPeriodInMs = collectingPeriodInMs;
|
|
155
159
|
this._setupTimer();
|
|
156
160
|
}
|
|
157
|
-
|
|
158
|
-
this._config.
|
|
161
|
+
setSamplingTick(samplingTick) {
|
|
162
|
+
this._config.samplingTick = samplingTick;
|
|
159
163
|
this._setupTimer();
|
|
160
164
|
}
|
|
161
165
|
get audioDesyncDetector() {
|
|
@@ -196,27 +200,74 @@ class ClientMonitor extends TypedEmitter_1.TypedEventEmitter {
|
|
|
196
200
|
getPeerConnectionStats(peerConnectionId) {
|
|
197
201
|
return this.storage.getPeerConnection(peerConnectionId);
|
|
198
202
|
}
|
|
203
|
+
get codecs() {
|
|
204
|
+
return [...this.storage.codecs()];
|
|
205
|
+
}
|
|
206
|
+
get inboundRtps() {
|
|
207
|
+
return [...this.storage.inboundRtps()];
|
|
208
|
+
}
|
|
209
|
+
get outboundRtps() {
|
|
210
|
+
return [...this.storage.outboundRtps()];
|
|
211
|
+
}
|
|
212
|
+
get remoteInboundRtps() {
|
|
213
|
+
return [...this.storage.remoteInboundRtps()];
|
|
214
|
+
}
|
|
215
|
+
get remoteOutboundRtps() {
|
|
216
|
+
return [...this.storage.remoteOutboundRtps()];
|
|
217
|
+
}
|
|
218
|
+
get mediaSources() {
|
|
219
|
+
return [...this.storage.mediaSources()];
|
|
220
|
+
}
|
|
221
|
+
get contributingSources() {
|
|
222
|
+
return [...this.storage.contributingSources()];
|
|
223
|
+
}
|
|
224
|
+
get dataChannels() {
|
|
225
|
+
return [...this.storage.dataChannels()];
|
|
226
|
+
}
|
|
227
|
+
get transceivers() {
|
|
228
|
+
return [...this.storage.transceivers()];
|
|
229
|
+
}
|
|
230
|
+
get senders() {
|
|
231
|
+
return [...this.storage.senders()];
|
|
232
|
+
}
|
|
233
|
+
get receivers() {
|
|
234
|
+
return [...this.storage.receivers()];
|
|
235
|
+
}
|
|
236
|
+
get transports() {
|
|
237
|
+
return [...this.storage.transports()];
|
|
238
|
+
}
|
|
239
|
+
get sctpTransports() {
|
|
240
|
+
return [...this.storage.sctpTransports()];
|
|
241
|
+
}
|
|
242
|
+
get iceCandidatePairs() {
|
|
243
|
+
return [...this.storage.iceCandidatePairs()];
|
|
244
|
+
}
|
|
245
|
+
get iceLocalCandidates() {
|
|
246
|
+
return [...this.storage.localCandidates()];
|
|
247
|
+
}
|
|
248
|
+
get iceRemoteCandidates() {
|
|
249
|
+
return [...this.storage.remoteCandidates()];
|
|
250
|
+
}
|
|
251
|
+
get certificates() {
|
|
252
|
+
return [...this.storage.certificates()];
|
|
253
|
+
}
|
|
254
|
+
get iceServers() {
|
|
255
|
+
return [...this.storage.iceServers()];
|
|
256
|
+
}
|
|
257
|
+
get peerConnections() {
|
|
258
|
+
return [...this.storage.peerConnections()];
|
|
259
|
+
}
|
|
260
|
+
get tracks() {
|
|
261
|
+
return [...this.storage.tracks()];
|
|
262
|
+
}
|
|
199
263
|
_setupTimer() {
|
|
200
|
-
|
|
264
|
+
this._timer && clearInterval(this._timer);
|
|
265
|
+
this._timer = undefined;
|
|
266
|
+
if (!this._config.collectingPeriodInMs)
|
|
201
267
|
return;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
action: () => this.collect().then(() => {
|
|
206
|
-
// empty
|
|
207
|
-
}),
|
|
208
|
-
fixedDelayInMs: this._config.collectingPeriodInMs,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
if (this._config.samplingPeriodInMs) {
|
|
212
|
-
this._timer.setSamplingAction({
|
|
213
|
-
action: async () => {
|
|
214
|
-
this.sample();
|
|
215
|
-
},
|
|
216
|
-
fixedDelayInMs: this._config.samplingPeriodInMs,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
this._timer.tickTimeInMs = this._config.tickingTimeInMs;
|
|
268
|
+
this._timer = setInterval(() => {
|
|
269
|
+
this.collect().catch(err => logger.error(err));
|
|
270
|
+
}, this._config.collectingPeriodInMs);
|
|
220
271
|
}
|
|
221
272
|
}
|
|
222
273
|
exports.ClientMonitor = ClientMonitor;
|
|
@@ -202,7 +202,7 @@ class PeerConnectionEntryManifest {
|
|
|
202
202
|
entry.droppedFrames = (stats.framesDropped ?? 0) - (entry.stats.framesDropped ?? 0);
|
|
203
203
|
entry.receivedSamples = (stats.totalSamplesReceived ?? 0) - (entry.stats.totalSamplesReceived ?? 0);
|
|
204
204
|
entry.silentConcealedSamples = (stats.silentConcealedSamples ?? 0) - (entry.stats.silentConcealedSamples ?? 0);
|
|
205
|
-
entry.fractionLoss = entry.lostPackets / (entry.lostPackets + entry.receivedPackets);
|
|
205
|
+
entry.fractionLoss = entry.lostPackets === 0 && entry.receivedPackets === 0 ? 0 : entry.lostPackets / (entry.lostPackets + entry.receivedPackets);
|
|
206
206
|
entry.stats = stats;
|
|
207
207
|
entry.visited = true;
|
|
208
208
|
if (entry.stats.kind === 'audio') {
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EAAE,4BAA4B,EAAE,MAAM,2CAA2C,CAAC;AAC9F,YAAY,EACR,aAAa,EACb,mBAAmB,EACnB,mBAAmB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,YAAY,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AACvF,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACjF,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,YAAY,EACR,QAAQ,GACX,MAAM,eAAe,CAAC;AAEvB,YAAY,EACR,YAAY,EACZ,kBAAkB,GACrB,MAAM,wBAAwB,CAAA;AAE/B,YAAY,EACR,UAAU,EACV,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EACzB,mBAAmB,GACtB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,QAAQ,MAAM,8BAA8B,CAAC;AAEzD,YAAY,EACX,YAAY,EACZ,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EACf,eAAe,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAyC,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG;IAC/D;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACvB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EAAE,4BAA4B,EAAE,MAAM,2CAA2C,CAAC;AAC9F,YAAY,EACR,aAAa,EACb,mBAAmB,EACnB,mBAAmB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,YAAY,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AACvF,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACjF,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,YAAY,EACR,QAAQ,GACX,MAAM,eAAe,CAAC;AAEvB,YAAY,EACR,YAAY,EACZ,kBAAkB,GACrB,MAAM,wBAAwB,CAAA;AAE/B,YAAY,EACR,UAAU,EACV,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EACzB,mBAAmB,GACtB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,QAAQ,MAAM,8BAA8B,CAAC;AAEzD,YAAY,EACX,YAAY,EACZ,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EACf,eAAe,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAyC,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG;IAC/D;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACvB,GAAG,aAAa,CAchB;AAED,OAAO,EACH,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,GACtB,MAAM,gBAAgB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -34,17 +34,17 @@ let loggerSet = false;
|
|
|
34
34
|
* @param config the given config to setup the observer
|
|
35
35
|
*/
|
|
36
36
|
function createClientMonitor(config) {
|
|
37
|
-
if (config && 0 < ((config?.collectingPeriodInMs ?? 0) + (config?.samplingPeriodInMs ?? 0))) {
|
|
38
|
-
if (!config.tickingTimeInMs) {
|
|
39
|
-
config.tickingTimeInMs = 1000;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
37
|
if (!loggerSet && config?.logLevel) {
|
|
43
38
|
(0, logger_1.addLoggerProcess)((0, logger_1.createConsoleLogger)(config.logLevel));
|
|
44
39
|
loggerSet = true;
|
|
45
40
|
}
|
|
41
|
+
if (config && !config.samplingTick)
|
|
42
|
+
config.samplingTick = 1;
|
|
46
43
|
return new ClientMonitor_1.ClientMonitor({
|
|
47
|
-
...(config ?? {
|
|
44
|
+
...(config ?? {
|
|
45
|
+
collectingPeriodInMs: 5000,
|
|
46
|
+
samplingTick: 1,
|
|
47
|
+
}),
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
exports.createClientMonitor = createClientMonitor;
|
package/package.json
CHANGED
package/lib/utils/Timer.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type Timer = ReturnType<typeof createTimer>;
|
|
2
|
-
export declare function createTimer(tickTimeInMs?: number): {
|
|
3
|
-
readonly active: boolean;
|
|
4
|
-
tickTimeInMs: number | undefined;
|
|
5
|
-
setCollectingAction: (config: {
|
|
6
|
-
action?: () => Promise<void>;
|
|
7
|
-
fixedDelayInMs?: number;
|
|
8
|
-
}) => void;
|
|
9
|
-
setSamplingAction: (config: {
|
|
10
|
-
action?: () => Promise<void>;
|
|
11
|
-
fixedDelayInMs?: number;
|
|
12
|
-
}) => void;
|
|
13
|
-
clear: () => void;
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=Timer.d.ts.map
|
package/lib/utils/Timer.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Timer.d.ts","sourceRoot":"","sources":["../../src/utils/Timer.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,wBAAgB,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM;;;kCAkDR;QAAE,MAAM,CAAC,EAAE,MAAM,QAAQ,IAAI,CAAC,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,KAAG,IAAI;gCAgBlE;QAAE,MAAM,CAAC,EAAE,MAAM,QAAQ,IAAI,CAAC,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,KAAG,IAAI;;EAoCtG"}
|
package/lib/utils/Timer.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createTimer = void 0;
|
|
4
|
-
const logger_1 = require("./logger");
|
|
5
|
-
const logger = (0, logger_1.createLogger)(`Timer`);
|
|
6
|
-
function createTimer(tickTimeInMs) {
|
|
7
|
-
let timer;
|
|
8
|
-
let collecting;
|
|
9
|
-
let sampling;
|
|
10
|
-
if (tickTimeInMs) {
|
|
11
|
-
setTickingTime(tickTimeInMs);
|
|
12
|
-
}
|
|
13
|
-
function setTickingTime(tickInMs) {
|
|
14
|
-
if (timer) {
|
|
15
|
-
clearInterval(timer);
|
|
16
|
-
timer = undefined;
|
|
17
|
-
}
|
|
18
|
-
if (!tickInMs) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
timer = setInterval(() => {
|
|
22
|
-
if (!collecting && !sampling) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
const now = Date.now();
|
|
26
|
-
let promise = Promise.resolve();
|
|
27
|
-
if (collecting) {
|
|
28
|
-
if (collecting.invoked) {
|
|
29
|
-
if (collecting.invoked + collecting.fixedDelayInMs <= now) {
|
|
30
|
-
promise = promise.then(() => collecting?.action() ?? Promise.resolve());
|
|
31
|
-
collecting.invoked = now;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
promise = promise.then(() => collecting?.action() ?? Promise.resolve());
|
|
36
|
-
collecting.invoked = now;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (sampling) {
|
|
40
|
-
if (sampling.invoked) {
|
|
41
|
-
if (sampling.invoked + sampling.fixedDelayInMs <= now) {
|
|
42
|
-
promise = promise.then(() => sampling?.action() ?? Promise.resolve());
|
|
43
|
-
sampling.invoked = now;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
promise = promise.then(() => sampling?.action() ?? Promise.resolve());
|
|
48
|
-
sampling.invoked = now;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
promise.catch(err => {
|
|
52
|
-
logger.warn(`Error occurred while executing timer action`, err);
|
|
53
|
-
});
|
|
54
|
-
}, tickInMs);
|
|
55
|
-
}
|
|
56
|
-
function setCollectingAction(config) {
|
|
57
|
-
const { action, fixedDelayInMs, } = config;
|
|
58
|
-
if (!action || !fixedDelayInMs) {
|
|
59
|
-
collecting = undefined;
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
collecting = {
|
|
63
|
-
action,
|
|
64
|
-
created: Date.now(),
|
|
65
|
-
fixedDelayInMs,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function setSamplingAction(config) {
|
|
69
|
-
const { action, fixedDelayInMs, } = config;
|
|
70
|
-
if (!action || !fixedDelayInMs) {
|
|
71
|
-
sampling = undefined;
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
sampling = {
|
|
75
|
-
action,
|
|
76
|
-
created: Date.now(),
|
|
77
|
-
fixedDelayInMs,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function clear() {
|
|
81
|
-
if (timer) {
|
|
82
|
-
clearInterval(timer);
|
|
83
|
-
timer = undefined;
|
|
84
|
-
}
|
|
85
|
-
collecting = undefined;
|
|
86
|
-
sampling = undefined;
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
get active() {
|
|
90
|
-
return !!timer;
|
|
91
|
-
},
|
|
92
|
-
set tickTimeInMs(value) {
|
|
93
|
-
setTickingTime(value);
|
|
94
|
-
},
|
|
95
|
-
setCollectingAction,
|
|
96
|
-
setSamplingAction,
|
|
97
|
-
clear,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
exports.createTimer = createTimer;
|