@observertc/observer-js 0.30.6-beta → 0.40.1-beta
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/lib/ObservedCall.d.ts +6 -12
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +24 -104
- package/lib/ObservedClient.d.ts +16 -32
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +381 -521
- package/lib/ObservedDataChannel.d.ts +68 -0
- package/lib/ObservedDataChannel.d.ts.map +1 -0
- package/lib/ObservedDataChannel.js +110 -0
- package/lib/ObservedInboundTrack.d.ts +3 -9
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +75 -157
- package/lib/ObservedOutboundTrack.d.ts +9 -9
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +77 -133
- package/lib/ObservedPeerConnection.d.ts +21 -15
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +85 -171
- package/lib/ObservedSfu.d.ts +5 -7
- package/lib/ObservedSfu.d.ts.map +1 -1
- package/lib/ObservedSfu.js +10 -74
- package/lib/Observer.d.ts +5 -6
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +28 -31
- package/lib/common/types.d.ts +0 -55
- package/lib/common/types.d.ts.map +1 -1
- package/lib/index.d.ts +5 -7
- package/lib/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ObservedCall.ts +27 -87
- package/src/ObservedClient.ts +451 -586
- package/src/ObservedDataChannel.ts +186 -0
- package/src/ObservedInboundTrack.ts +18 -72
- package/src/ObservedOutboundTrack.ts +36 -60
- package/src/ObservedPeerConnection.ts +79 -112
- package/src/ObservedSfu.ts +11 -46
- package/src/Observer.ts +11 -16
- package/src/common/types.ts +0 -69
- package/src/index.ts +5 -7
- package/lib/models/Models.d.ts +0 -642
- package/lib/models/Models.d.ts.map +0 -1
- package/lib/models/Models.js +0 -481
- package/lib/models/samples_pb.d.ts +0 -2452
- package/lib/models/samples_pb.d.ts.map +0 -1
- package/lib/models/samples_pb.js +0 -1495
- package/lib/storages/ObserverStorage.d.ts +0 -87
- package/lib/storages/ObserverStorage.d.ts.map +0 -1
- package/lib/storages/ObserverStorage.js +0 -2
- package/lib/storages/SimpleStorage.d.ts +0 -19
- package/lib/storages/SimpleStorage.d.ts.map +0 -1
- package/lib/storages/SimpleStorage.js +0 -106
- package/lib/storages/StorageProvider.d.ts +0 -16
- package/lib/storages/StorageProvider.d.ts.map +0 -1
- package/lib/storages/StorageProvider.js +0 -29
- package/src/models/Models.ts +0 -1103
- package/src/models/samples_pb.ts +0 -4061
- package/src/storages/ObserverStorage.ts +0 -99
- package/src/storages/SimpleStorage.ts +0 -120
- package/src/storages/StorageProvider.ts +0 -42
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
3
|
+
import { DataChannel } from '@observertc/sample-schemas-js';
|
|
4
|
+
import { ClientDataChannelReport } from '@observertc/report-schemas-js';
|
|
5
|
+
|
|
6
|
+
export type ObservedDataChannelState = 'connecting' | 'open' | 'closing' | 'closed';
|
|
7
|
+
|
|
8
|
+
export type ObservedDataChannelModel = {
|
|
9
|
+
channelId: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ObservedDataChannelEvents = {
|
|
13
|
+
update: [],
|
|
14
|
+
close: [],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ObservedInboundTrackStats = {
|
|
18
|
+
ssrc: number;
|
|
19
|
+
bitrate: number;
|
|
20
|
+
fractionLost: number;
|
|
21
|
+
rttInMs?: number;
|
|
22
|
+
lostPackets?: number;
|
|
23
|
+
receivedPackets?: number;
|
|
24
|
+
receivedFrames?: number;
|
|
25
|
+
decodedFrames?: number;
|
|
26
|
+
droppedFrames?: number;
|
|
27
|
+
receivedSamples?: number;
|
|
28
|
+
silentConcealedSamples?: number;
|
|
29
|
+
fractionLoss?: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// {
|
|
33
|
+
// [Property in keyof ObservedInboundTrackStats<K>]: ObservedInboundTrackStats<K>[Property];
|
|
34
|
+
// }
|
|
35
|
+
|
|
36
|
+
export declare interface ObservedDataChannel {
|
|
37
|
+
on<U extends keyof ObservedDataChannelEvents>(event: U, listener: (...args: ObservedDataChannelEvents[U]) => void): this;
|
|
38
|
+
off<U extends keyof ObservedDataChannelEvents>(event: U, listener: (...args: ObservedDataChannelEvents[U]) => void): this;
|
|
39
|
+
once<U extends keyof ObservedDataChannelEvents>(event: U, listener: (...args: ObservedDataChannelEvents[U]) => void): this;
|
|
40
|
+
emit<U extends keyof ObservedDataChannelEvents>(event: U, ...args: ObservedDataChannelEvents[U]): boolean;
|
|
41
|
+
update(sample: DataChannel, timestamp: number): void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class ObservedDataChannel extends EventEmitter {
|
|
45
|
+
public readonly created = Date.now();
|
|
46
|
+
|
|
47
|
+
private _stats?: DataChannel;
|
|
48
|
+
|
|
49
|
+
private _closed = false;
|
|
50
|
+
private _updated = Date.now();
|
|
51
|
+
public bitrate = 0;
|
|
52
|
+
|
|
53
|
+
public totalReceivedMessages = 0;
|
|
54
|
+
public totalSentMessages = 0;
|
|
55
|
+
public totalBytesReceived = 0;
|
|
56
|
+
public totalBytesSent = 0;
|
|
57
|
+
|
|
58
|
+
public deltaReceivedMessages = 0;
|
|
59
|
+
public deltaSentMessages = 0;
|
|
60
|
+
public deltaBytesReceived = 0;
|
|
61
|
+
public deltaBytesSent = 0;
|
|
62
|
+
|
|
63
|
+
public constructor(
|
|
64
|
+
private readonly _model: ObservedDataChannelModel,
|
|
65
|
+
public readonly peerConnection: ObservedPeerConnection,
|
|
66
|
+
) {
|
|
67
|
+
super();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public get serviceId() {
|
|
71
|
+
return this.peerConnection.serviceId;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public get roomId() {
|
|
75
|
+
return this.peerConnection.roomId;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public get callId() {
|
|
79
|
+
return this.peerConnection.callId;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public get clientId() {
|
|
83
|
+
return this.peerConnection.clientId;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public get mediaUnitId() {
|
|
87
|
+
return this.peerConnection.mediaUnitId;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public get peerConnectionId() {
|
|
91
|
+
return this.peerConnection.peerConnectionId;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public get channelId() {
|
|
95
|
+
return this._model.channelId;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public get updated() {
|
|
99
|
+
return this._updated;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public get state(): ObservedDataChannelState | undefined {
|
|
103
|
+
return this._stats?.state as ObservedDataChannelState | undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public get label() {
|
|
107
|
+
return this._stats?.label;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public get protocol() {
|
|
111
|
+
return this._stats?.protocol;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public get reports() {
|
|
115
|
+
return this.peerConnection.reports;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public get stats() {
|
|
119
|
+
return this._stats;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public get closed() {
|
|
123
|
+
return this._closed;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public close() {
|
|
127
|
+
if (this._closed) return;
|
|
128
|
+
|
|
129
|
+
this._closed = true;
|
|
130
|
+
|
|
131
|
+
this.emit('close');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public resetMetrics() {
|
|
135
|
+
this.bitrate = 0;
|
|
136
|
+
this.totalReceivedMessages = 0;
|
|
137
|
+
this.totalSentMessages = 0;
|
|
138
|
+
this.totalBytesReceived = 0;
|
|
139
|
+
this.totalBytesSent = 0;
|
|
140
|
+
this.deltaReceivedMessages = 0;
|
|
141
|
+
this.deltaSentMessages = 0;
|
|
142
|
+
this.deltaBytesReceived = 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public update(sample: DataChannel, timestamp: number) {
|
|
146
|
+
if (this._closed) return;
|
|
147
|
+
|
|
148
|
+
const now = Date.now();
|
|
149
|
+
|
|
150
|
+
const report: ClientDataChannelReport = {
|
|
151
|
+
serviceId: this.peerConnection.client.call.serviceId,
|
|
152
|
+
roomId: this.peerConnection.client.call.roomId,
|
|
153
|
+
callId: this.peerConnection.client.call.callId,
|
|
154
|
+
clientId: this.peerConnection.client.clientId,
|
|
155
|
+
userId: this.peerConnection.client.userId,
|
|
156
|
+
mediaUnitId: this.peerConnection.client.mediaUnitId,
|
|
157
|
+
...sample,
|
|
158
|
+
timestamp,
|
|
159
|
+
sampleSeq: -1,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
this.reports.addClientDataChannelReport(report);
|
|
163
|
+
|
|
164
|
+
sample.bytesReceived;
|
|
165
|
+
sample.bytesSent;
|
|
166
|
+
sample.messageReceived;
|
|
167
|
+
sample.messageSent;
|
|
168
|
+
|
|
169
|
+
const elapsedTimeInMs = Math.max(1, now - this._updated);
|
|
170
|
+
|
|
171
|
+
this.bitrate = ((sample.bytesReceived ?? 0) - (this._stats?.bytesReceived ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
172
|
+
this.deltaSentMessages = (sample.messageSent ?? 0) - (this._stats?.messageSent ?? 0);
|
|
173
|
+
this.deltaReceivedMessages = (sample.messageReceived ?? 0) - (this._stats?.messageReceived ?? 0);
|
|
174
|
+
this.deltaBytesSent = (sample.bytesSent ?? 0) - (this._stats?.bytesSent ?? 0);
|
|
175
|
+
this.deltaBytesReceived = (sample.bytesReceived ?? 0) - (this._stats?.bytesReceived ?? 0);
|
|
176
|
+
|
|
177
|
+
this.totalBytesReceived = sample.bytesReceived ?? 0;
|
|
178
|
+
this.totalBytesSent = sample.bytesSent ?? 0;
|
|
179
|
+
this.totalReceivedMessages = sample.messageReceived ?? 0;
|
|
180
|
+
this.totalSentMessages = sample.messageSent ?? 0;
|
|
181
|
+
|
|
182
|
+
this._stats = sample;
|
|
183
|
+
this._updated = timestamp;
|
|
184
|
+
this.emit('update');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { StorageProvider } from './storages/StorageProvider';
|
|
3
|
-
import * as Models from './models/Models';
|
|
4
2
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
5
3
|
import { InboundAudioTrack, InboundVideoTrack } from '@observertc/sample-schemas-js';
|
|
6
4
|
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
7
5
|
import { InboundAudioTrackReport, InboundVideoTrackReport } from '@observertc/report-schemas-js';
|
|
8
6
|
import { MediaKind } from './common/types';
|
|
9
|
-
import { createSingleExecutor } from './common/SingleExecutor';
|
|
10
7
|
|
|
11
|
-
export type
|
|
8
|
+
export type ObservedInboundTrackModel<K extends MediaKind> = {
|
|
12
9
|
trackId: string;
|
|
13
10
|
kind: K;
|
|
14
11
|
sfuStreamId?: string;
|
|
@@ -51,35 +48,9 @@ export declare interface ObservedInboundTrack<Kind extends MediaKind> {
|
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
54
|
-
public
|
|
55
|
-
config: ObservedInboundTrackConfig<K>,
|
|
56
|
-
peerConnection: ObservedPeerConnection,
|
|
57
|
-
storageProvider: StorageProvider,
|
|
58
|
-
) {
|
|
59
|
-
const model = new Models.InboundTrack({
|
|
60
|
-
serviceId: peerConnection.client.serviceId,
|
|
61
|
-
roomId: peerConnection.client.roomId,
|
|
62
|
-
callId: peerConnection.client.callId,
|
|
63
|
-
clientId: peerConnection.client.clientId,
|
|
64
|
-
mediaUnitId: peerConnection.client.mediaUnitId,
|
|
65
|
-
peerConnectionId: peerConnection.peerConnectionId,
|
|
66
|
-
trackId: config.trackId,
|
|
67
|
-
kind: config.kind,
|
|
68
|
-
sfuStreamId: config.sfuStreamId,
|
|
69
|
-
sfuSinkId: config.sfuSinkId,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const alreadyInserted = await storageProvider.inboundTrackStorage.insert(config.trackId, model);
|
|
73
|
-
|
|
74
|
-
if (alreadyInserted) throw new Error(`InboundAudioTrack with id ${config.trackId} already exists`);
|
|
75
|
-
|
|
76
|
-
return new ObservedInboundTrack<K>(model, peerConnection, storageProvider);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public created = Date.now();
|
|
51
|
+
public readonly created = Date.now();
|
|
80
52
|
|
|
81
53
|
private readonly _stats = new Map<number, ObservedInboundTrackStats<Kind>>();
|
|
82
|
-
private readonly _execute = createSingleExecutor();
|
|
83
54
|
|
|
84
55
|
private _closed = false;
|
|
85
56
|
private _updated = Date.now();
|
|
@@ -106,52 +77,43 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
106
77
|
public deltaReceivedSamples = 0;
|
|
107
78
|
public deltaSilentConcealedSamples = 0;
|
|
108
79
|
|
|
109
|
-
|
|
110
|
-
private readonly _model:
|
|
80
|
+
public constructor(
|
|
81
|
+
private readonly _model: ObservedInboundTrackModel<Kind>,
|
|
111
82
|
public readonly peerConnection: ObservedPeerConnection,
|
|
112
|
-
private readonly _storageProvider: StorageProvider,
|
|
113
83
|
) {
|
|
114
84
|
super();
|
|
115
85
|
}
|
|
116
86
|
|
|
117
87
|
public get serviceId() {
|
|
118
|
-
|
|
119
|
-
return this._model.serviceId!;
|
|
88
|
+
return this.peerConnection.serviceId;
|
|
120
89
|
}
|
|
121
90
|
|
|
122
91
|
public get roomId() {
|
|
123
|
-
|
|
124
|
-
return this._model.roomId!;
|
|
92
|
+
return this.peerConnection.roomId;
|
|
125
93
|
}
|
|
126
94
|
|
|
127
95
|
public get callId() {
|
|
128
|
-
|
|
129
|
-
return this._model.callId!;
|
|
96
|
+
return this.peerConnection.callId;
|
|
130
97
|
}
|
|
131
98
|
|
|
132
99
|
public get clientId() {
|
|
133
|
-
|
|
134
|
-
return this._model.clientId!;
|
|
100
|
+
return this.peerConnection.clientId;
|
|
135
101
|
}
|
|
136
102
|
|
|
137
103
|
public get mediaUnitId() {
|
|
138
|
-
|
|
139
|
-
return this._model.mediaUnitId!;
|
|
104
|
+
return this.peerConnection.mediaUnitId;
|
|
140
105
|
}
|
|
141
106
|
|
|
142
107
|
public get peerConnectionId() {
|
|
143
|
-
|
|
144
|
-
return this._model.peerConnectionId!;
|
|
108
|
+
return this.peerConnection.peerConnectionId;
|
|
145
109
|
}
|
|
146
110
|
|
|
147
111
|
public get trackId() {
|
|
148
|
-
|
|
149
|
-
return this._model.trackId!;
|
|
112
|
+
return this._model.trackId;
|
|
150
113
|
}
|
|
151
114
|
|
|
152
115
|
public get kind(): Kind {
|
|
153
|
-
|
|
154
|
-
return this._model.kind! as Kind;
|
|
116
|
+
return this._model.kind as Kind;
|
|
155
117
|
}
|
|
156
118
|
|
|
157
119
|
public get sfuStreamId() {
|
|
@@ -174,10 +136,6 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
174
136
|
return this.peerConnection.reports;
|
|
175
137
|
}
|
|
176
138
|
|
|
177
|
-
public get uptimeInMs() {
|
|
178
|
-
return this._updated - this.created;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
139
|
public set remoteOutboundTrack(track: ObservedOutboundTrack<Kind> | undefined) {
|
|
182
140
|
if (this._closed) return;
|
|
183
141
|
if (this._remoteOutboundTrack) return;
|
|
@@ -202,9 +160,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
202
160
|
|
|
203
161
|
this._closed = true;
|
|
204
162
|
|
|
205
|
-
this.
|
|
206
|
-
.catch(() => void 0)
|
|
207
|
-
.finally(() => this.emit('close'));
|
|
163
|
+
this.emit('close');
|
|
208
164
|
}
|
|
209
165
|
|
|
210
166
|
public resetMetrics() {
|
|
@@ -220,10 +176,10 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
220
176
|
this.fractionLoss = 0;
|
|
221
177
|
}
|
|
222
178
|
|
|
223
|
-
public
|
|
179
|
+
public update(sample: ObservedInboundTrackStatsUpdate<Kind>, timestamp: number) {
|
|
224
180
|
if (this._closed) return;
|
|
225
|
-
|
|
226
|
-
|
|
181
|
+
|
|
182
|
+
const now = Date.now();
|
|
227
183
|
const report: InboundAudioTrackReport | InboundVideoTrackReport = {
|
|
228
184
|
serviceId: this.peerConnection.client.call.serviceId,
|
|
229
185
|
roomId: this.peerConnection.client.call.roomId,
|
|
@@ -247,15 +203,13 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
247
203
|
|
|
248
204
|
if (!this._model.sfuStreamId && sample.sfuStreamId) {
|
|
249
205
|
this._model.sfuStreamId = sample.sfuStreamId;
|
|
250
|
-
executeSave = true;
|
|
251
206
|
}
|
|
252
207
|
|
|
253
208
|
if (!this._model.sfuSinkId && sample.sfuSinkId) {
|
|
254
209
|
this._model.sfuSinkId = sample.sfuSinkId;
|
|
255
|
-
executeSave = true;
|
|
256
210
|
}
|
|
257
211
|
|
|
258
|
-
const elapsedTimeInMs = Math.max(1,
|
|
212
|
+
const elapsedTimeInMs = Math.max(1, now - this._updated);
|
|
259
213
|
const lastStat = this._stats.get(sample.ssrc);
|
|
260
214
|
const rttInMs = sample.roundTripTime ? sample.roundTripTime * 1000 : undefined;
|
|
261
215
|
const bitrate = ((sample.bytesReceived ?? 0) - (lastStat?.bytesReceived ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
@@ -318,15 +272,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
318
272
|
this.deltaSilentConcealedSamples = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.silentConcealedSamples ?? 0), 0);
|
|
319
273
|
this.fractionLoss = 0 < this.deltaReceivedPackets && 0 < this.deltaLostPackets ? (this.deltaLostPackets / (this.deltaReceivedPackets + this.deltaLostPackets)) : 0;
|
|
320
274
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
this._updated = timestamp;
|
|
275
|
+
this._updated = now;
|
|
324
276
|
this.emit('update');
|
|
325
277
|
}
|
|
326
|
-
|
|
327
|
-
private async _save() {
|
|
328
|
-
if (this._closed) throw new Error(`OutboundTrack ${this.trackId} is closed`);
|
|
329
|
-
|
|
330
|
-
return this._storageProvider.inboundTrackStorage.set(this.trackId, this._model);
|
|
331
|
-
}
|
|
332
278
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { StorageProvider } from './storages/StorageProvider';
|
|
3
|
-
import * as Models from './models/Models';
|
|
4
2
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
5
3
|
import { OutboundAudioTrack, OutboundVideoTrack } from '@observertc/sample-schemas-js';
|
|
6
4
|
import { ObservedInboundTrack } from './ObservedInboundTrack';
|
|
7
5
|
import { OutboundAudioTrackReport, OutboundVideoTrackReport } from '@observertc/report-schemas-js';
|
|
8
6
|
import { MediaKind } from './common/types';
|
|
9
|
-
import { createSingleExecutor } from './common/SingleExecutor';
|
|
10
7
|
|
|
11
|
-
export type
|
|
8
|
+
export type ObservedOutboundTrackModel<K extends MediaKind> = {
|
|
12
9
|
trackId: string;
|
|
13
10
|
kind: K;
|
|
14
11
|
sfuStreamId?: string;
|
|
@@ -46,29 +43,7 @@ export declare interface ObservedOutboundTrack<Kind extends MediaKind> {
|
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
49
|
-
public
|
|
50
|
-
config: ObservedOutboundTrackConfig<K>,
|
|
51
|
-
peerConnection: ObservedPeerConnection,
|
|
52
|
-
storageProvider: StorageProvider,
|
|
53
|
-
) {
|
|
54
|
-
const model = new Models.OutboundTrack({
|
|
55
|
-
serviceId: peerConnection.client.serviceId,
|
|
56
|
-
roomId: peerConnection.client.roomId,
|
|
57
|
-
callId: peerConnection.client.callId,
|
|
58
|
-
clientId: peerConnection.client.clientId,
|
|
59
|
-
mediaUnitId: peerConnection.client.mediaUnitId,
|
|
60
|
-
peerConnectionId: peerConnection.peerConnectionId,
|
|
61
|
-
trackId: config.trackId,
|
|
62
|
-
kind: config.kind,
|
|
63
|
-
sfuStreamId: config.sfuStreamId,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const alreadyInserted = await storageProvider.outboundTrackStorage.insert(config.trackId, model);
|
|
67
|
-
|
|
68
|
-
if (alreadyInserted) throw new Error(`OutboundAudioTrack with id ${config.trackId} already exists`);
|
|
69
|
-
|
|
70
|
-
return new ObservedOutboundTrack<K>(model, peerConnection, storageProvider);
|
|
71
|
-
}
|
|
46
|
+
public readonly created = Date.now();
|
|
72
47
|
|
|
73
48
|
public bitrate = 0;
|
|
74
49
|
public rttInMs?: number;
|
|
@@ -84,31 +59,49 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
84
59
|
public deltaSentFrames = 0;
|
|
85
60
|
public deltaEncodedFrames = 0;
|
|
86
61
|
|
|
87
|
-
public created = Date.now();
|
|
88
|
-
|
|
89
62
|
private readonly _stats = new Map<number, ObservedOutboundTrackStats<Kind>>();
|
|
90
|
-
private readonly _execute = createSingleExecutor();
|
|
91
63
|
|
|
92
64
|
private _closed = false;
|
|
93
65
|
private _updated = Date.now();
|
|
94
66
|
private _remoteInboundTracks = new Map<string, ObservedInboundTrack<Kind>>();
|
|
95
67
|
|
|
96
|
-
|
|
97
|
-
private readonly _model:
|
|
68
|
+
public constructor(
|
|
69
|
+
private readonly _model: ObservedOutboundTrackModel<Kind>,
|
|
98
70
|
public readonly peerConnection: ObservedPeerConnection,
|
|
99
|
-
private readonly _storageProvider: StorageProvider,
|
|
100
71
|
) {
|
|
101
72
|
super();
|
|
102
73
|
}
|
|
103
74
|
|
|
75
|
+
public get serviceId() {
|
|
76
|
+
return this.peerConnection.serviceId;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public get roomId() {
|
|
80
|
+
return this.peerConnection.roomId;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public get callId() {
|
|
84
|
+
return this.peerConnection.callId;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public get clientId() {
|
|
88
|
+
return this.peerConnection.clientId;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public get mediaUnitId() {
|
|
92
|
+
return this.peerConnection.mediaUnitId;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public get peerConnectionId() {
|
|
96
|
+
return this.peerConnection.peerConnectionId;
|
|
97
|
+
}
|
|
98
|
+
|
|
104
99
|
public get kind(): Kind {
|
|
105
|
-
|
|
106
|
-
return this._model.kind! as Kind;
|
|
100
|
+
return this._model.kind as Kind;
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
public get trackId() {
|
|
110
|
-
|
|
111
|
-
return this._model.trackId!;
|
|
104
|
+
return this._model.trackId;
|
|
112
105
|
}
|
|
113
106
|
|
|
114
107
|
public get sfuStreamId() {
|
|
@@ -131,22 +124,15 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
131
124
|
return this._stats;
|
|
132
125
|
}
|
|
133
126
|
|
|
134
|
-
public get uptimeInMs() {
|
|
135
|
-
return this._updated - this.created;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
127
|
public get closed() {
|
|
139
128
|
return this._closed;
|
|
140
129
|
}
|
|
141
130
|
|
|
142
131
|
public close() {
|
|
143
132
|
if (this._closed) return;
|
|
144
|
-
|
|
145
133
|
this._closed = true;
|
|
146
134
|
|
|
147
|
-
this.
|
|
148
|
-
.catch(() => void 0)
|
|
149
|
-
.finally(() => this.emit('close'));
|
|
135
|
+
this.emit('close');
|
|
150
136
|
}
|
|
151
137
|
|
|
152
138
|
public resetMetrics() {
|
|
@@ -160,10 +146,10 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
160
146
|
this.deltaEncodedFrames = 0;
|
|
161
147
|
}
|
|
162
148
|
|
|
163
|
-
public
|
|
149
|
+
public update(sample: ObservedOutboundTrackStatsUpdate<Kind>, timestamp: number): void {
|
|
164
150
|
if (this._closed) return;
|
|
165
|
-
|
|
166
|
-
|
|
151
|
+
|
|
152
|
+
const now = Date.now();
|
|
167
153
|
const report: OutboundAudioTrackReport | OutboundVideoTrackReport = {
|
|
168
154
|
serviceId: this.peerConnection.client.serviceId,
|
|
169
155
|
roomId: this.peerConnection.client.call.roomId,
|
|
@@ -180,7 +166,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
180
166
|
if (this.kind === 'audio') this.reports.addOutboundAudioTrackReport(report);
|
|
181
167
|
else if (this.kind === 'video') this.reports.addOutboundVideoTrackReport(report);
|
|
182
168
|
|
|
183
|
-
const elapsedTimeInMs = Math.max(1,
|
|
169
|
+
const elapsedTimeInMs = Math.max(1, now - this._updated);
|
|
184
170
|
const lastStat = this._stats.get(sample.ssrc);
|
|
185
171
|
const rttInMs = sample.roundTripTime ? sample.roundTripTime * 1000 : undefined;
|
|
186
172
|
const bitrate = ((sample.bytesSent ?? 0) - (lastStat?.bytesSent ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
@@ -237,13 +223,9 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
237
223
|
|
|
238
224
|
if (this.kind === 'audio') this.peerConnection.client.call.sfuStreamIdToOutboundAudioTrack.set(this._model.sfuStreamId, this as ObservedOutboundTrack<'audio'>);
|
|
239
225
|
else if (this.kind === 'video') this.peerConnection.client.call.sfuStreamIdToOutboundVideoTrack.set(this._model.sfuStreamId, this as ObservedOutboundTrack<'video'>);
|
|
240
|
-
|
|
241
|
-
executeSave = true;
|
|
242
226
|
}
|
|
243
227
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
this._updated = timestamp;
|
|
228
|
+
this._updated = now;
|
|
247
229
|
this.emit('update');
|
|
248
230
|
}
|
|
249
231
|
|
|
@@ -257,10 +239,4 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
257
239
|
|
|
258
240
|
this._remoteInboundTracks.set(track.trackId, track);
|
|
259
241
|
}
|
|
260
|
-
|
|
261
|
-
private async _save() {
|
|
262
|
-
if (this._closed) throw new Error(`OutboundTrack ${this.trackId} is closed`);
|
|
263
|
-
|
|
264
|
-
return this._storageProvider.outboundTrackStorage.set(this.trackId, this._model);
|
|
265
|
-
}
|
|
266
242
|
}
|