@livedigital/client 2.22.1 → 2.23.0-get-stats.1
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/dist/engine/Peer.d.ts +3 -1
- package/dist/engine/PeerConsumer.d.ts +2 -1
- package/dist/engine/media/tracks/BaseTrack.d.ts +4 -1
- package/dist/engine/media/tracks/PeerTrack.d.ts +4 -1
- package/dist/index.es.js +1 -1
- package/dist/index.js +1 -1
- package/dist/types/common.d.ts +54 -0
- package/package.json +1 -1
- package/src/engine/Peer.ts +25 -0
- package/src/engine/PeerConsumer.ts +19 -0
- package/src/engine/media/tracks/BaseTrack.ts +66 -2
- package/src/engine/media/tracks/PeerTrack.ts +39 -1
- package/src/types/common.ts +59 -0
package/dist/types/common.d.ts
CHANGED
|
@@ -236,6 +236,60 @@ export declare enum DeviceErrors {
|
|
|
236
236
|
DeviceIsBusy = "DeviceIsBusy",
|
|
237
237
|
NotAllowedError = "NotAllowedError"
|
|
238
238
|
}
|
|
239
|
+
export declare type TrackInboundStats = {
|
|
240
|
+
consumerId: string;
|
|
241
|
+
codec?: RTCRtpCodecParameters;
|
|
242
|
+
currentSpatialLayerParams?: SpatialLayerParams;
|
|
243
|
+
availableSpatialLayers?: SpatialLayerParams[];
|
|
244
|
+
requestedSpatialLayer?: number;
|
|
245
|
+
score: number;
|
|
246
|
+
dtlsState?: RTCDtlsTransportState;
|
|
247
|
+
rtcStats?: ExtendedRTCInboundRtpStreamStats;
|
|
248
|
+
};
|
|
249
|
+
export declare type TrackOutboundStats = {
|
|
250
|
+
producerId?: string;
|
|
251
|
+
codec?: RTCRtpCodecParameters;
|
|
252
|
+
dtlsState?: RTCDtlsTransportState;
|
|
253
|
+
rtcStats?: RTCOutboundRtpStreamStats;
|
|
254
|
+
};
|
|
255
|
+
export declare type PeerTrackInfo = {
|
|
256
|
+
trackId: string;
|
|
257
|
+
readyState: MediaStreamTrackState;
|
|
258
|
+
isRemote: boolean;
|
|
259
|
+
kind: MediaKind;
|
|
260
|
+
label: TrackLabel;
|
|
261
|
+
paused: boolean;
|
|
262
|
+
width?: number;
|
|
263
|
+
height?: number;
|
|
264
|
+
frameRate?: number;
|
|
265
|
+
aspectRatio?: number;
|
|
266
|
+
trackInboundStats?: TrackInboundStats;
|
|
267
|
+
trackOutboundStats?: TrackOutboundStats;
|
|
268
|
+
};
|
|
269
|
+
export declare type BaseTrackInfo = {
|
|
270
|
+
trackId: string;
|
|
271
|
+
readyState: MediaStreamTrackState;
|
|
272
|
+
kind: MediaKind;
|
|
273
|
+
label: TrackLabel;
|
|
274
|
+
paused: boolean;
|
|
275
|
+
width?: number;
|
|
276
|
+
height?: number;
|
|
277
|
+
frameRate?: number;
|
|
278
|
+
aspectRatio?: number;
|
|
279
|
+
trackOutboundStats?: TrackOutboundStats;
|
|
280
|
+
};
|
|
281
|
+
export declare type PeerInfo = {
|
|
282
|
+
id: string;
|
|
283
|
+
appData: Record<string, unknown>;
|
|
284
|
+
role: Role;
|
|
285
|
+
isBroadcaster: boolean;
|
|
286
|
+
channelIds: string[];
|
|
287
|
+
appId: string;
|
|
288
|
+
uid?: string;
|
|
289
|
+
loginDate: Date;
|
|
290
|
+
connectionQuality: number;
|
|
291
|
+
tracks: PeerTrackInfo[];
|
|
292
|
+
};
|
|
239
293
|
export declare type UpdatePeerAppDataPayload = {
|
|
240
294
|
peerId: string;
|
|
241
295
|
appData: Record<string, unknown>;
|
package/package.json
CHANGED
package/src/engine/Peer.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ChangePreferredLayersPayload,
|
|
9
9
|
Role,
|
|
10
10
|
ProducerSetMaxSpatialLayer,
|
|
11
|
+
PeerInfo,
|
|
11
12
|
} from '../types/common';
|
|
12
13
|
import EnhancedEventEmitter from '../EnhancedEventEmitter';
|
|
13
14
|
import Engine from './index';
|
|
@@ -109,6 +110,10 @@ class Peer {
|
|
|
109
110
|
return this.id === this.engine.mySocketId;
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
get isBroadcaster(): boolean {
|
|
114
|
+
return this.channelIds.length > 1;
|
|
115
|
+
}
|
|
116
|
+
|
|
112
117
|
public get publishedMedia(): PayloadOfPublishedMedia[] {
|
|
113
118
|
return Array.from(this.producers.values()).map((producer) => ({
|
|
114
119
|
producerId: producer.id,
|
|
@@ -157,6 +162,26 @@ class Peer {
|
|
|
157
162
|
}
|
|
158
163
|
}
|
|
159
164
|
|
|
165
|
+
async getInfo(): Promise<PeerInfo> {
|
|
166
|
+
try {
|
|
167
|
+
return {
|
|
168
|
+
id: this.id,
|
|
169
|
+
appData: this.appData,
|
|
170
|
+
role: this.role,
|
|
171
|
+
isBroadcaster: this.isBroadcaster,
|
|
172
|
+
channelIds: this.channelIds,
|
|
173
|
+
appId: this.appId,
|
|
174
|
+
uid: this.uid,
|
|
175
|
+
loginDate: this.loginDate,
|
|
176
|
+
connectionQuality: this.overallConnectionQuality,
|
|
177
|
+
tracks: await Promise.all(Array.from(this.tracks.values()).map((track) => track.getInfo())),
|
|
178
|
+
};
|
|
179
|
+
} catch (error) {
|
|
180
|
+
this.logger.error('getInfo()', { peer: this, error });
|
|
181
|
+
throw new Error('Error get info');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
160
185
|
private handleNewProducer(producerData: ProducerData): void {
|
|
161
186
|
if (this.producers.get(producerData.id)) {
|
|
162
187
|
return;
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ExtendedRTCInboundRtpStreamStats,
|
|
7
7
|
LogLevel,
|
|
8
8
|
SpatialLayerParams,
|
|
9
|
+
TrackInboundStats,
|
|
9
10
|
} from '../types/common';
|
|
10
11
|
import Logger from './Logger';
|
|
11
12
|
|
|
@@ -167,6 +168,24 @@ class PeerConsumer {
|
|
|
167
168
|
this.currentMaxSpatialLayer = spatialLayer;
|
|
168
169
|
}
|
|
169
170
|
|
|
171
|
+
async getStats(): Promise<TrackInboundStats | undefined> {
|
|
172
|
+
try {
|
|
173
|
+
return {
|
|
174
|
+
consumerId: this.consumer.id,
|
|
175
|
+
codec: this.consumer.rtpParameters.codecs.find((codec) => codec.mimeType !== 'rtx'),
|
|
176
|
+
score: this.score,
|
|
177
|
+
dtlsState: this.consumer.rtpReceiver?.transport?.state,
|
|
178
|
+
availableSpatialLayers: this.availableSpatialLayers,
|
|
179
|
+
currentSpatialLayerParams: this.currentSpatialLayerParams,
|
|
180
|
+
requestedSpatialLayer: this.requestedSpatialLayer,
|
|
181
|
+
rtcStats: await this.getInboundRTPStreamStats(),
|
|
182
|
+
};
|
|
183
|
+
} catch (error) {
|
|
184
|
+
this.logger.debug('getStats()', { error });
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
170
189
|
async getInboundRTPStreamStats(): Promise<ExtendedRTCInboundRtpStreamStats> {
|
|
171
190
|
return new Promise((resolve, reject) => {
|
|
172
191
|
const getRTCStatsReport = async (attempt = 0) => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Producer } from 'mediasoup-client/lib/Producer';
|
|
2
2
|
import { MediaKind } from 'mediasoup-client/lib/RtpParameters';
|
|
3
3
|
import {
|
|
4
|
+
BaseTrackInfo,
|
|
4
5
|
EncoderConfig,
|
|
5
6
|
LogLevel,
|
|
6
7
|
SocketResponse,
|
|
7
|
-
TrackLabel,
|
|
8
|
+
TrackLabel, TrackOutboundStats,
|
|
8
9
|
TrackProduceParams,
|
|
9
10
|
} from '../../../types/common';
|
|
10
11
|
import Logger from '../../Logger';
|
|
@@ -41,7 +42,7 @@ class BaseTrack {
|
|
|
41
42
|
|
|
42
43
|
#producerRestarted = false;
|
|
43
44
|
|
|
44
|
-
#clientEventEmitter: EnhancedEventEmitter;
|
|
45
|
+
readonly #clientEventEmitter: EnhancedEventEmitter;
|
|
45
46
|
|
|
46
47
|
#closed = false;
|
|
47
48
|
|
|
@@ -379,6 +380,69 @@ class BaseTrack {
|
|
|
379
380
|
throw new Error('Can`t resume track');
|
|
380
381
|
}
|
|
381
382
|
}
|
|
383
|
+
|
|
384
|
+
async getInfo(): Promise<BaseTrackInfo> {
|
|
385
|
+
const {
|
|
386
|
+
width, height, frameRate, aspectRatio,
|
|
387
|
+
} = this.#mediaStreamTrack.getSettings();
|
|
388
|
+
return {
|
|
389
|
+
trackId: this.#mediaStreamTrack.id,
|
|
390
|
+
readyState: this.#mediaStreamTrack.readyState,
|
|
391
|
+
kind: this.kind,
|
|
392
|
+
label: this.label,
|
|
393
|
+
width,
|
|
394
|
+
height,
|
|
395
|
+
frameRate,
|
|
396
|
+
aspectRatio,
|
|
397
|
+
paused: this.isPaused,
|
|
398
|
+
trackOutboundStats: await this.getStats(),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async getStats(): Promise<TrackOutboundStats | undefined> {
|
|
403
|
+
try {
|
|
404
|
+
return {
|
|
405
|
+
producerId: this.producer?.id,
|
|
406
|
+
codec: this.producer?.rtpParameters.codecs.find((codec) => codec.mimeType !== 'rtx'),
|
|
407
|
+
dtlsState: this.producer?.rtpSender?.transport?.state,
|
|
408
|
+
rtcStats: await this.getOutboundRTPStreamStats(),
|
|
409
|
+
};
|
|
410
|
+
} catch (error) {
|
|
411
|
+
this.logger.debug('getStats()', { error });
|
|
412
|
+
return undefined;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private getOutboundRTPStreamStats(): Promise<RTCOutboundRtpStreamStats> {
|
|
417
|
+
return new Promise((resolve, reject) => {
|
|
418
|
+
const getRTCStatsReport = async (attempt = 0) => {
|
|
419
|
+
if (!this.producer) {
|
|
420
|
+
throw new Error('Producer is missed');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
const rtcStatsReport = await this.producer.getStats();
|
|
425
|
+
const outboundRTPStreamStats: RTCOutboundRtpStreamStats = Array.from(rtcStatsReport.values())
|
|
426
|
+
.find((stat) => stat.type === 'outbound-rtp');
|
|
427
|
+
if (!outboundRTPStreamStats && attempt < 5) {
|
|
428
|
+
setTimeout(() => getRTCStatsReport(attempt + 1), 150);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (attempt >= 5 && !outboundRTPStreamStats) {
|
|
433
|
+
reject(new Error('OutboundRTPStreamStat not exist'));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
resolve(outboundRTPStreamStats);
|
|
437
|
+
} catch (error) {
|
|
438
|
+
reject(new Error('Can not get RTCStatsReport'));
|
|
439
|
+
this.logger.debug('getOutboundRTPStreamStats()', { error });
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
getRTCStatsReport();
|
|
444
|
+
});
|
|
445
|
+
}
|
|
382
446
|
}
|
|
383
447
|
|
|
384
448
|
export default BaseTrack;
|
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
PreferredLayersParams,
|
|
4
4
|
SetConsumerPriorityParams,
|
|
5
5
|
SpatialLayerParams,
|
|
6
|
-
|
|
6
|
+
PeerTrackInfo,
|
|
7
|
+
TrackLabel, TrackOutboundStats,
|
|
7
8
|
} from '../../../types/common';
|
|
8
9
|
import Logger from '../../Logger';
|
|
9
10
|
import { MEDIASOUP_EVENTS, PEER_EVENTS } from '../../../constants/events';
|
|
@@ -57,6 +58,10 @@ class PeerTrack {
|
|
|
57
58
|
this.#peerEventEmitter.safeEmit(PEER_EVENTS.trackStart, this);
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
get isRemote(): boolean {
|
|
62
|
+
return !!this.consumer;
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
get mediaStreamTrack(): MediaStreamTrack {
|
|
61
66
|
return this.#mediaStreamTrack;
|
|
62
67
|
}
|
|
@@ -238,6 +243,39 @@ class PeerTrack {
|
|
|
238
243
|
return this.consumer.availableSpatialLayers;
|
|
239
244
|
}
|
|
240
245
|
|
|
246
|
+
async getInfo(): Promise<PeerTrackInfo> {
|
|
247
|
+
const {
|
|
248
|
+
width, height, frameRate, aspectRatio,
|
|
249
|
+
} = this.#mediaStreamTrack.getSettings();
|
|
250
|
+
return {
|
|
251
|
+
trackId: this.#mediaStreamTrack.id,
|
|
252
|
+
readyState: this.#mediaStreamTrack.readyState,
|
|
253
|
+
isRemote: this.isRemote,
|
|
254
|
+
kind: this.kind,
|
|
255
|
+
label: this.label,
|
|
256
|
+
width,
|
|
257
|
+
height,
|
|
258
|
+
frameRate,
|
|
259
|
+
aspectRatio,
|
|
260
|
+
paused: this.#paused,
|
|
261
|
+
trackInboundStats: await this.consumer?.getStats(),
|
|
262
|
+
trackOutboundStats: await this.getOutboundStats(),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private async getOutboundStats(): Promise<TrackOutboundStats | undefined> {
|
|
267
|
+
if (this.isRemote) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const outboundTrack = this.#engine.media.getAllTracks().find((track) => track.getLabel() === this.label);
|
|
272
|
+
if (!outboundTrack) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return outboundTrack.getStats();
|
|
277
|
+
}
|
|
278
|
+
|
|
241
279
|
private async requestMaxSpatialLayer(consumerId: string, spatialLayer: number): Promise<void> {
|
|
242
280
|
try {
|
|
243
281
|
if (!this.consumer) {
|
package/src/types/common.ts
CHANGED
|
@@ -274,6 +274,65 @@ export enum DeviceErrors {
|
|
|
274
274
|
NotAllowedError = 'NotAllowedError',
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
export type TrackInboundStats = {
|
|
278
|
+
consumerId: string,
|
|
279
|
+
codec?: RTCRtpCodecParameters,
|
|
280
|
+
currentSpatialLayerParams?: SpatialLayerParams,
|
|
281
|
+
availableSpatialLayers?: SpatialLayerParams[],
|
|
282
|
+
requestedSpatialLayer?: number,
|
|
283
|
+
score: number,
|
|
284
|
+
dtlsState?: RTCDtlsTransportState,
|
|
285
|
+
rtcStats?: ExtendedRTCInboundRtpStreamStats,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export type TrackOutboundStats = {
|
|
289
|
+
producerId?: string,
|
|
290
|
+
codec?: RTCRtpCodecParameters,
|
|
291
|
+
dtlsState?: RTCDtlsTransportState,
|
|
292
|
+
rtcStats?: RTCOutboundRtpStreamStats,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export type PeerTrackInfo = {
|
|
296
|
+
trackId: string,
|
|
297
|
+
readyState: MediaStreamTrackState,
|
|
298
|
+
isRemote: boolean,
|
|
299
|
+
kind: MediaKind,
|
|
300
|
+
label: TrackLabel,
|
|
301
|
+
paused: boolean,
|
|
302
|
+
width?: number,
|
|
303
|
+
height?: number,
|
|
304
|
+
frameRate?: number,
|
|
305
|
+
aspectRatio?: number,
|
|
306
|
+
trackInboundStats?: TrackInboundStats,
|
|
307
|
+
trackOutboundStats?: TrackOutboundStats,
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export type BaseTrackInfo = {
|
|
311
|
+
trackId: string,
|
|
312
|
+
readyState: MediaStreamTrackState,
|
|
313
|
+
kind: MediaKind,
|
|
314
|
+
label: TrackLabel,
|
|
315
|
+
paused: boolean,
|
|
316
|
+
width?: number,
|
|
317
|
+
height?: number,
|
|
318
|
+
frameRate?: number,
|
|
319
|
+
aspectRatio?: number,
|
|
320
|
+
trackOutboundStats?: TrackOutboundStats,
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export type PeerInfo = {
|
|
324
|
+
id: string,
|
|
325
|
+
appData: Record<string, unknown>,
|
|
326
|
+
role: Role,
|
|
327
|
+
isBroadcaster: boolean;
|
|
328
|
+
channelIds: string[],
|
|
329
|
+
appId: string,
|
|
330
|
+
uid?: string,
|
|
331
|
+
loginDate: Date,
|
|
332
|
+
connectionQuality: number,
|
|
333
|
+
tracks: PeerTrackInfo[],
|
|
334
|
+
};
|
|
335
|
+
|
|
277
336
|
export type UpdatePeerAppDataPayload = {
|
|
278
337
|
peerId: string,
|
|
279
338
|
appData: Record<string, unknown>,
|