@livedigital/client 1.7.0 → 1.10.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.
Files changed (37) hide show
  1. package/dist/constants/events.d.ts +1 -0
  2. package/dist/engine/Peer.d.ts +16 -35
  3. package/dist/engine/PeerProducer.d.ts +2 -1
  4. package/dist/engine/index.d.ts +15 -11
  5. package/dist/engine/media/Consumer.d.ts +0 -1
  6. package/dist/engine/media/VideoConsumer.d.ts +1 -9
  7. package/dist/engine/media/index.d.ts +9 -11
  8. package/dist/engine/media/tracks/AudioTrack.d.ts +9 -0
  9. package/dist/engine/media/tracks/BaseTrack.d.ts +23 -0
  10. package/dist/engine/media/tracks/TrackWithCodecOptions.d.ts +4 -0
  11. package/dist/engine/media/tracks/TrackWithEncodings.d.ts +4 -0
  12. package/dist/engine/media/tracks/VideoTrack.d.ts +13 -0
  13. package/dist/engine/network/LoadBalancerClient.d.ts +7 -1
  14. package/dist/engine/network/index.d.ts +5 -2
  15. package/dist/engine/system/index.d.ts +10 -19
  16. package/dist/index.d.ts +16 -22
  17. package/dist/index.es.js +15 -1
  18. package/dist/index.js +15 -1
  19. package/dist/types/common.d.ts +57 -7
  20. package/package.json +11 -7
  21. package/src/constants/events.ts +1 -0
  22. package/src/engine/Peer.ts +132 -337
  23. package/src/engine/PeerProducer.ts +8 -2
  24. package/src/engine/index.ts +172 -197
  25. package/src/engine/media/Consumer.ts +0 -4
  26. package/src/engine/media/VideoConsumer.ts +1 -18
  27. package/src/engine/media/index.ts +35 -35
  28. package/src/engine/media/tracks/AudioTrack.ts +18 -0
  29. package/src/engine/media/tracks/BaseTrack.ts +70 -0
  30. package/src/engine/media/tracks/TrackWithCodecOptions.ts +5 -0
  31. package/src/engine/media/tracks/TrackWithEncodings.ts +5 -0
  32. package/src/engine/media/tracks/VideoTrack.ts +29 -0
  33. package/src/engine/network/LoadBalancerClient.ts +18 -4
  34. package/src/engine/network/index.ts +8 -3
  35. package/src/engine/system/index.ts +64 -198
  36. package/src/index.ts +39 -68
  37. package/src/types/common.ts +71 -8
@@ -1,13 +1,15 @@
1
1
  import { ConsumerOptions } from 'mediasoup-client/lib/Consumer';
2
2
  import {
3
- ChangePreferredLayersParams,
4
3
  ConsumerScoreChangedPayload,
5
4
  PreferredLayersParams,
6
5
  ProducerData,
7
- ProducerKind,
8
6
  ProducerScoreChangedPayload,
9
7
  SetConsumerPriorityParams,
10
8
  SocketResponse,
9
+ ConnectionQuality,
10
+ StartTrackPayload,
11
+ EndTrackPayload,
12
+ PayloadOfPublishedMedia, PayloadOfUnpublishedMedia,
11
13
  } from '../types/common';
12
14
  import Consumer from './media/Consumer';
13
15
  import VideoConsumer from './media/VideoConsumer';
@@ -16,7 +18,6 @@ import Engine from './index';
16
18
  import { MEDIASOUP_EVENTS, PEER_EVENTS } from '../constants/events';
17
19
  import Logger from './Logger';
18
20
  import PeerProducer from './PeerProducer';
19
- import { ConnectionQuality } from '../types/common';
20
21
 
21
22
  interface PeerConstructor {
22
23
  id: string;
@@ -51,13 +52,9 @@ class Peer {
51
52
 
52
53
  public appData: Record<string, unknown>;
53
54
 
54
- private videoProducer?: PeerProducer;
55
+ private producers: Map<string, PeerProducer> = new Map();
55
56
 
56
- private audioProducer?: PeerProducer;
57
-
58
- private videoConsumer?: VideoConsumer;
59
-
60
- private audioConsumer?: Consumer;
57
+ private consumers: Map<string, Consumer | VideoConsumer> = new Map();
61
58
 
62
59
  private readonly engine: Engine;
63
60
 
@@ -75,8 +72,6 @@ class Peer {
75
72
  appId,
76
73
  loginDate = new Date(),
77
74
  producers = [],
78
- videoConsumer,
79
- audioConsumer,
80
75
  engine,
81
76
  appData,
82
77
  uid,
@@ -88,8 +83,6 @@ class Peer {
88
83
  this.appData = appData || {};
89
84
  this.uid = uid;
90
85
  this.engine = engine;
91
- this.videoConsumer = videoConsumer;
92
- this.audioConsumer = audioConsumer;
93
86
  this.logger = new Logger('Peer');
94
87
  producers.forEach(this.handleNewProducer.bind(this));
95
88
  this.handlePeerEvents();
@@ -99,245 +92,121 @@ class Peer {
99
92
  return this._observer;
100
93
  }
101
94
 
102
- public get isPublishedVideo(): boolean {
103
- return !!this.videoProducer;
104
- }
105
-
106
- public get isPublishedAudio(): boolean {
107
- return !!this.audioProducer;
108
- }
109
-
110
- public get hasVideo(): boolean {
111
- return !!this.videoConsumer;
112
- }
113
-
114
- public get hasAudio(): boolean {
115
- return !!this.audioConsumer;
116
- }
117
-
118
- public get videoTrack(): MediaStreamTrack | undefined {
119
- if (this.isMe) {
120
- return this.engine.system.videoStream?.getVideoTracks()[0];
121
- }
122
-
123
- return this.videoConsumer?.track;
124
- }
125
-
126
- public get audioTrack(): MediaStreamTrack | undefined {
127
- if (this.isMe) {
128
- return this.engine.system.audioStream?.getVideoTracks()[0];
129
- }
130
-
131
- return this.audioConsumer?.track;
132
- }
133
-
134
- public get isVideoPaused(): boolean {
135
- return this.videoConsumer?.paused || false;
136
- }
137
-
138
- public get isAudioPaused(): boolean {
139
- return this.audioConsumer?.paused || false;
140
- }
141
-
142
- public get videoCodec(): string | undefined {
143
- if (!this.videoConsumer) {
144
- return undefined;
145
- }
146
-
147
- return this.videoConsumer.rtpParameters.codecs[0].mimeType.split('/')[1];
148
- }
149
-
150
- public get audioCodec(): string | undefined {
151
- if (!this.audioConsumer) {
152
- return undefined;
153
- }
154
-
155
- return this.audioConsumer.rtpParameters.codecs[0].mimeType.split('/')[1];
156
- }
157
-
158
95
  public get isMe(): boolean {
159
96
  return this.id === this.engine.mySocketId;
160
97
  }
161
98
 
162
- public async subscribeVideo(): Promise<void> {
163
- if (!this.videoProducer) {
164
- this.logger.warn('subscribeVideo()', { message: 'This peer has no published video', peer: this });
165
- return;
166
- }
167
-
168
- if (this.videoConsumer) {
169
- this.logger.warn('subscribeVideo()', { message: 'Already subscribed this peer\'s video', peer: this });
170
- return;
171
- }
172
-
173
- await this.createConsumer(this.videoProducer);
174
- }
175
-
176
- public async subscribeAudio(): Promise<void> {
177
- if (!this.audioProducer) {
178
- this.logger.warn('subscribeAudio()', { message: 'This peer has no published audio', peer: this });
179
- return;
180
- }
181
-
182
- if (this.audioConsumer) {
183
- this.logger.warn('subscribeAudio()', { message: 'Already subscribed this peer\'s audio', peer: this });
184
- return;
185
- }
186
-
187
- await this.createConsumer(this.audioProducer);
99
+ public get publishedMedia(): PayloadOfPublishedMedia[] {
100
+ return Array.from(this.producers.values()).map((producer) => ({
101
+ producerId: producer.id,
102
+ kind: producer.kind,
103
+ label: producer.label,
104
+ }));
188
105
  }
189
106
 
190
- public async unSubscribeVideo(): Promise<void> {
191
- if (!this.videoConsumer) {
192
- this.logger.warn('unSubscribeVideo()', { message: 'This peer has no subscribed video', peer: this });
107
+ public async subscribe(producerId: string): Promise<void> {
108
+ const producer = this.producers.get(producerId);
109
+ if (!producer) {
110
+ this.logger.warn('subscribe()', { message: 'Peer does not have a producer', peer: this, producerId });
193
111
  return;
194
112
  }
195
113
 
196
- await this.closeConsumer(this.videoConsumer);
197
- this.videoConsumer = undefined;
198
- this.observer.safeEmit('track-end', { kind: 'video' });
199
- }
200
-
201
- public async unSubscribeAudio(): Promise<void> {
202
- if (!this.audioConsumer) {
203
- this.logger.warn('unSubscribeAudio()', { message: 'This peer has no subscribed audio', peer: this });
114
+ const consumer = this.getAllConsumers().find((item) => item.producerId === producerId);
115
+ if (consumer) {
116
+ this.logger.warn('subscribe()', { message: 'Already subscribed to producer', peer: this, producerId });
204
117
  return;
205
118
  }
206
119
 
207
- await this.closeConsumer(this.audioConsumer);
208
- this.audioConsumer = undefined;
209
- this.observer.safeEmit('track-end', { kind: 'audio' });
120
+ await this.createConsumer(producer);
210
121
  }
211
122
 
212
- public async setMinResolution(): Promise<void> {
213
- if (!this.videoConsumer || this.videoConsumer?.spatialLayers === 0) {
123
+ public async setMinResolution(consumerId: string): Promise<void> {
124
+ const consumer = this.consumers.get(consumerId);
125
+ if (!(consumer instanceof VideoConsumer) || consumer.spatialLayers === 0) {
214
126
  return;
215
127
  }
216
128
 
217
- await this.changeConsumerPreferredLayers({
218
- spatialLayer: 0,
219
- });
129
+ await this.changeConsumerPreferredLayers(consumer, { spatialLayer: 0 });
220
130
  }
221
131
 
222
- public async setMediumResolution(): Promise<void> {
223
- if (!this.videoConsumer || this.videoConsumer?.spatialLayers === 0) {
132
+ public async setMediumResolution(consumerId: string): Promise<void> {
133
+ const consumer = this.consumers.get(consumerId);
134
+ if (!(consumer instanceof VideoConsumer) || consumer.spatialLayers === 0) {
224
135
  return;
225
136
  }
226
137
 
227
- const mediumLayer = this.videoConsumer.spatialLayers > 2
228
- ? this.videoConsumer.spatialLayers - 2
229
- : this.videoConsumer.spatialLayers;
230
-
231
- await this.changeConsumerPreferredLayers({
232
- spatialLayer: mediumLayer,
233
- });
138
+ const mediumLayer = consumer.spatialLayers > 2
139
+ ? consumer.spatialLayers - 2
140
+ : consumer.spatialLayers;
141
+ await this.changeConsumerPreferredLayers(consumer, { spatialLayer: mediumLayer });
234
142
  }
235
143
 
236
- public async setMaxResolution(): Promise<void> {
237
- if (!this.videoConsumer || this.videoConsumer.spatialLayers === 0) {
144
+ public async setMaxResolution(consumerId: string): Promise<void> {
145
+ const consumer = this.consumers.get(consumerId);
146
+ if (!(consumer instanceof VideoConsumer) || consumer.spatialLayers === 0) {
238
147
  return;
239
148
  }
240
149
 
241
- await this.changeConsumerPreferredLayers({
242
- spatialLayer: this.videoConsumer.spatialLayers - 1,
150
+ await this.changeConsumerPreferredLayers(consumer, {
151
+ spatialLayer: consumer.spatialLayers - 1,
243
152
  });
244
153
  }
245
154
 
246
- public async pauseVideo(): Promise<void> {
247
- if (!this.videoConsumer) {
248
- this.logger.warn('pauseVideo()', { message: 'This peer has no subscribed video', peer: this });
249
- return;
250
- }
251
-
252
- if (this.videoConsumer.paused) {
253
- this.logger.warn('pauseVideo()', { message: 'Already paused', peer: this });
254
- return;
255
- }
256
-
257
- try {
258
- await this.pauseRemoteConsumer(this.videoConsumer?.id);
259
- this.videoConsumer.pause();
260
- this.logger.debug('pauseVideo()', { peer: this });
261
- } catch (err) {
262
- this.logger.error('pauseVideo()', err);
263
- }
264
- }
265
-
266
- public async pauseAudio(): Promise<void> {
267
- if (!this.audioConsumer) {
268
- this.logger.warn('pauseAudio()', { message: 'This peer has no subscribed audio', peer: this });
155
+ public async pause(consumerId: string): Promise<void> {
156
+ const consumer = this.consumers.get(consumerId);
157
+ if (!consumer) {
158
+ this.logger.warn('pause()', { message: 'This peer has no consumer to pause', peer: this, consumerId });
269
159
  return;
270
160
  }
271
161
 
272
- if (this.audioConsumer.paused) {
273
- this.logger.warn('pauseAudio()', { message: 'Already paused', peer: this });
162
+ if (consumer.paused) {
163
+ this.logger.warn('pause()', { message: 'Already paused', peer: this, consumerId });
274
164
  return;
275
165
  }
276
166
 
277
167
  try {
278
- await this.pauseRemoteConsumer(this.audioConsumer?.id);
279
- this.audioConsumer.pause();
280
- this.logger.debug('pauseAudio()', { peer: this });
168
+ await this.pauseRemoteConsumer(consumer.id);
169
+ consumer.pause();
170
+ this.logger.debug('pause()', { peer: this, consumerId });
281
171
  } catch (err) {
282
- this.logger.error('pauseAudio()', err);
172
+ this.logger.error('pause()', err);
283
173
  }
284
174
  }
285
175
 
286
- public async resumeVideo(): Promise<void> {
287
- if (!this.videoConsumer) {
288
- this.logger.warn('resumeVideo()', { message: 'This peer has no subscribed video', peer: this });
176
+ public async resume(consumerId: string): Promise<void> {
177
+ const consumer = this.consumers.get(consumerId);
178
+ if (!consumer) {
179
+ this.logger.warn('resume()', { message: 'This peer has no consumer to resume', peer: this, consumerId });
289
180
  return;
290
181
  }
291
182
 
292
- if (!this.videoConsumer.paused) {
293
- this.logger.warn('resumeVideo()', { message: 'Video is not paused', peer: this });
183
+ if (!consumer.paused) {
184
+ this.logger.warn('resume()', { message: 'Already playing', peer: this, consumerId });
294
185
  return;
295
186
  }
296
187
 
297
188
  try {
298
- await this.resumeRemoteConsumer(this.videoConsumer?.id);
299
- this.videoConsumer.resume();
300
- this.logger.debug('resumeVideo()', { peer: this });
189
+ await this.resumeRemoteConsumer(consumer.id);
190
+ consumer.resume();
191
+ this.logger.debug('resume()', { peer: this });
301
192
  } catch (err) {
302
- this.logger.error('resumeVideo()', err);
193
+ this.logger.error('resume()', err);
303
194
  }
304
195
  }
305
196
 
306
- public async resumeAudio(): Promise<void> {
307
- if (!this.audioConsumer) {
308
- this.logger.warn('resumeAudio()', { message: 'This peer has no subscribed audio', peer: this });
309
- return;
310
- }
311
-
312
- if (this.audioConsumer.paused) {
313
- this.logger.warn('resumeAudio()', { message: 'Audio is not paused', peer: this });
314
- return;
315
- }
316
- try {
317
- await this.resumeRemoteConsumer(this.audioConsumer?.id);
318
- this.audioConsumer.resume();
319
- this.logger.debug('resumeAudio()', { peer: this });
320
- } catch (err) {
321
- this.logger.error('resumeAudio()', err);
322
- }
323
- }
324
-
325
- public async setVideoStreamPriority(priority: number): Promise<void> {
326
- if (!this.videoConsumer) {
327
- this.logger.warn('setVideoStreamPriority()', { message: 'This peer has no subscribed audio', peer: this });
328
- return;
329
- }
330
-
331
- await this.setConsumerPriority({ consumerId: this.videoConsumer.id, priority });
332
- }
197
+ public async setPriority(consumerId: string, priority: number): Promise<void> {
198
+ const consumer = this.consumers.get(consumerId);
199
+ if (!consumer) {
200
+ this.logger.warn('setPriority()', {
201
+ message: 'This peer has no consumer to change priority',
202
+ peer: this,
203
+ consumerId,
204
+ });
333
205
 
334
- public async setAudioStreamPriority(priority: number): Promise<void> {
335
- if (!this.audioConsumer) {
336
- this.logger.warn('setAudioStreamPriority()', { message: 'This peer has no subscribed audio', peer: this });
337
206
  return;
338
207
  }
339
208
 
340
- await this.setConsumerPriority({ consumerId: this.audioConsumer.id, priority });
209
+ await this.setConsumerPriority({ consumerId, priority });
341
210
  }
342
211
 
343
212
  private async setConsumerPriority(params: SetConsumerPriorityParams): Promise<void> {
@@ -372,91 +241,46 @@ class Peer {
372
241
  await this.engine.network.socket.request(MEDIASOUP_EVENTS.resumeConsumer, { consumerId: consumer.id });
373
242
 
374
243
  if (producer.kind === 'audio') {
375
- this.audioConsumer = new Consumer(consumer);
244
+ this.consumers.set(consumer.id, new Consumer(consumer));
376
245
  }
377
246
 
378
247
  if (producer.kind === 'video') {
379
- this.videoConsumer = new VideoConsumer(consumer);
248
+ this.consumers.set(consumer.id, new VideoConsumer(consumer));
380
249
  }
381
250
 
382
251
  this.logger.debug(`Subscribed for ${producer.kind}`, { peer: this });
383
- this.observer.safeEmit(PEER_EVENTS.trackStart, { kind: producer.kind, track: consumer.track });
252
+ this.observer.safeEmit(PEER_EVENTS.trackStart, {
253
+ producerId: producer.id,
254
+ consumerId: consumer.id,
255
+ track: consumer.track,
256
+ label: producer.label,
257
+ } as StartTrackPayload);
384
258
  } catch (error) {
385
259
  this.logger.error('createConsumer()', producer, error);
386
260
  throw new Error('Error subscribe media');
387
261
  }
388
262
  }
389
263
 
390
- private async closeConsumer(consumer: Consumer | VideoConsumer): Promise<void> {
391
- try {
392
- await this.engine.network.socket.request(MEDIASOUP_EVENTS.closeConsumer, {
393
- peerId: this.engine.mySocketId,
394
- consumerId: consumer.id,
395
- });
396
-
397
- consumer.close();
398
- this.logger.warn('Unsubscribed media', { peer: this, kind: consumer.kind });
399
- } catch (err) {
400
- this.logger.debug('closeConsumer()', { peer: this, consumer, error: err });
401
- throw new Error('Error unsubscribe media');
402
- }
403
- }
404
-
405
- private async changeConsumerPreferredLayers({ spatialLayer, temporalLayer }: PreferredLayersParams): Promise<void> {
406
- if (!this.videoConsumer) {
407
- return;
408
- }
409
-
410
- const {
411
- spatialLayer: oldSpatialLayer,
412
- temporalLayer: oldTemporalLayer,
413
- } = this.videoConsumer.currentPreferredLayers;
414
-
415
- if (oldSpatialLayer === spatialLayer || oldTemporalLayer === temporalLayer) {
416
- return;
417
- }
418
-
264
+ private async changeConsumerPreferredLayers(
265
+ consumer: VideoConsumer,
266
+ { spatialLayer, temporalLayer }: PreferredLayersParams,
267
+ ): Promise<void> {
419
268
  try {
420
- this.videoConsumer.currentPreferredLayers = { spatialLayer, temporalLayer };
421
269
  await this.engine.network.socket.request(MEDIASOUP_EVENTS.consumerChangePreferredLayers, {
422
- consumerId: this.videoConsumer.id,
270
+ consumerId: consumer.id,
423
271
  spatialLayer,
424
272
  temporalLayer,
425
273
  });
426
274
  } catch (err) {
427
275
  this.logger.error('changeConsumerPreferredLayers()', {
428
276
  peer: this,
429
- consumer: this.videoConsumer,
277
+ consumer,
430
278
  error: err,
431
279
  });
432
280
  throw new Error('Error change preferred layer');
433
281
  }
434
282
  }
435
283
 
436
- private setVideoProducer(producer: PeerProducer): void {
437
- if (producer.kind !== 'video') {
438
- throw new Error('Error kind of producer');
439
- }
440
-
441
- this.videoProducer = producer;
442
- }
443
-
444
- private setAudioProducer(producer: PeerProducer): void {
445
- if (producer.kind !== 'audio') {
446
- throw new Error('Error kind of producer');
447
- }
448
-
449
- this.audioProducer = producer;
450
- }
451
-
452
- private removeVideoProducer(): void {
453
- this.videoProducer = undefined;
454
- }
455
-
456
- private removeAudioProducer(): void {
457
- this.audioProducer = undefined;
458
- }
459
-
460
284
  private async pauseRemoteConsumer(consumerId: string): Promise<SocketResponse> {
461
285
  return this.engine.network.socket.request(MEDIASOUP_EVENTS.pauseConsumer, { consumerId });
462
286
  }
@@ -467,87 +291,62 @@ class Peer {
467
291
 
468
292
  private handleNewProducer(producerData: ProducerData): void {
469
293
  const producer = new PeerProducer(producerData);
470
- if (producer.kind === ProducerKind.VIDEO) {
471
- this.setVideoProducer(producer);
472
- } else {
473
- this.setAudioProducer(producer);
474
- }
475
-
294
+ this.producers.set(producer.id, producer);
476
295
  this.logger.debug('Peer published media:', { peer: this, producer });
477
- this.observer.safeEmit(PEER_EVENTS.mediaPublished, { kind: producer.kind });
296
+ this.observer.safeEmit(PEER_EVENTS.mediaPublished, {
297
+ producerId: producer.id,
298
+ kind: producer.kind,
299
+ label: producer.label,
300
+ } as PayloadOfPublishedMedia);
478
301
  }
479
302
 
480
303
  private handlePeerEvents(): void {
481
304
  this.observer.on(MEDIASOUP_EVENTS.newProducer, this.handleNewProducer.bind(this));
482
305
 
483
306
  this.observer.on(MEDIASOUP_EVENTS.producerClose, (producer: ProducerData) => {
484
- if (producer.kind === ProducerKind.VIDEO) {
485
- this.removeVideoProducer();
486
- } else {
487
- this.removeAudioProducer();
488
- }
489
-
307
+ this.producers.delete(producer.id);
490
308
  this.logger.debug('Peer unpublished media:', { peer: this, producer });
491
- this.observer.safeEmit(PEER_EVENTS.mediaUnPublished, { kind: producer.kind });
309
+ this.observer.safeEmit(PEER_EVENTS.mediaUnPublished, {
310
+ producerId: producer.id,
311
+ kind: producer.kind,
312
+ label: producer.label,
313
+ } as PayloadOfUnpublishedMedia);
492
314
  });
493
315
 
494
316
  this.observer.on(MEDIASOUP_EVENTS.closeConsumer, (consumerId) => {
495
- if (this.videoConsumer?.id === consumerId) {
496
- this.videoConsumer?.close();
497
- this.videoConsumer = undefined;
498
- this.observer.safeEmit(PEER_EVENTS.trackEnd, { kind: 'video' });
499
- this.logger.debug('Peer video track was ended:', { peer: this });
317
+ const consumer = this.consumers.get(consumerId);
318
+ if (!consumer) {
500
319
  return;
501
320
  }
502
321
 
503
- if (this.audioConsumer?.id === consumerId) {
504
- this.audioConsumer?.close();
505
- this.audioConsumer = undefined;
506
- this.logger.debug('Peer audio track was ended:', { peer: this });
507
- this.observer.safeEmit(PEER_EVENTS.trackEnd, { kind: 'audio' });
508
- }
322
+ consumer.close();
323
+ this.consumers.delete(consumerId);
324
+ this.observer.safeEmit(PEER_EVENTS.trackEnd, {
325
+ producerId: consumer.producerId,
326
+ kind: consumer.kind,
327
+ label: consumer.appData.producerData.label,
328
+ } as EndTrackPayload);
329
+ this.logger.debug('Peer video track was ended:', { peer: this });
509
330
  });
510
331
 
511
332
  this.observer.on(MEDIASOUP_EVENTS.pauseConsumer, (consumerId) => {
512
- if (this.videoConsumer?.id === consumerId) {
513
- this.videoConsumer?.pause();
514
- this.logger.debug('Peer video track was paused:', { peer: this });
333
+ const consumer = this.consumers.get(consumerId);
334
+ if (!consumer) {
515
335
  return;
516
336
  }
517
337
 
518
- if (this.audioConsumer?.id === consumerId) {
519
- this.audioConsumer?.pause();
520
- this.logger.debug('Peer audio track was paused:', { peer: this });
521
- }
338
+ consumer.pause();
339
+ this.logger.debug('Peer video track was paused:', { peer: this });
522
340
  });
523
341
 
524
342
  this.observer.on(MEDIASOUP_EVENTS.resumeConsumer, (consumerId) => {
525
- if (this.videoConsumer?.id === consumerId) {
526
- this.videoConsumer?.resume();
527
- this.logger.debug('Peer video track was resumed:', { peer: this });
343
+ const consumer = this.consumers.get(consumerId);
344
+ if (!consumer) {
528
345
  return;
529
346
  }
530
347
 
531
- if (this.audioConsumer?.id === consumerId) {
532
- this.audioConsumer?.resume();
533
- this.logger.debug('Peer video track was resumed:', { peer: this });
534
- }
535
- });
536
-
537
- this.observer.on(MEDIASOUP_EVENTS.consumerChangePreferredLayers, ({
538
- spatialLayer, temporalLayer,
539
- }: ChangePreferredLayersParams) => {
540
- if (!this.videoConsumer) {
541
- return;
542
- }
543
-
544
- this.videoConsumer.setCurrentSpatialLayer(spatialLayer);
545
- this.videoConsumer.setCurrentTemporalLayer(temporalLayer);
546
- this.logger.debug('Peer video track was changed preferred layers:', {
547
- peer: this,
548
- spatialLayer,
549
- temporalLayer,
550
- });
348
+ consumer.resume();
349
+ this.logger.debug('Peer video track was paused:', { peer: this });
551
350
  });
552
351
 
553
352
  // set outgoing connection quality for remote peer
@@ -556,8 +355,8 @@ class Peer {
556
355
  return;
557
356
  }
558
357
 
559
- const consumer = payload.kind === 'audio' ? this.audioConsumer : this.videoConsumer;
560
- if (consumer?.id !== payload.consumerId) {
358
+ const consumer = this.consumers.get(payload.consumerId);
359
+ if (!consumer) {
561
360
  return;
562
361
  }
563
362
 
@@ -565,22 +364,14 @@ class Peer {
565
364
  consumer.score = score;
566
365
  consumer.producerScore = producerScore;
567
366
 
568
- const peerProducerScores = [];
569
- if (this.audioConsumer) {
570
- peerProducerScores.push(this.audioConsumer.producerScore);
571
- }
572
-
573
- if (this.videoConsumer) {
574
- peerProducerScores.push(this.videoConsumer.producerScore);
575
- }
576
-
367
+ const peerProducerScores: number[] = this.getAllConsumers().map((item) => item.producerScore);
577
368
  const minScore = Math.min(...peerProducerScores);
578
- this.outgoingConnectionQuality = this.getConnectionQualityByScore(minScore);
369
+ this.outgoingConnectionQuality = Peer.getConnectionQualityByScore(minScore);
579
370
  this.emitConnectionQuality();
580
371
  });
581
372
 
582
373
  // set incoming connection quality for current peer
583
- this.observer.on(MEDIASOUP_EVENTS.consumerScoreChanged, (payload: ConsumerScoreChangedPayload) => {
374
+ this.observer.on(MEDIASOUP_EVENTS.consumerScoreChanged, () => {
584
375
  if (!this.isMe) {
585
376
  return;
586
377
  }
@@ -588,14 +379,11 @@ class Peer {
588
379
  const allPeersLowQualityConsumersScores = [] as number[];
589
380
  // pick scores of low quality consumers (consumerScore < producerScore)
590
381
  this.engine.peers.forEach((peer) => {
591
- const { videoConsumer, audioConsumer } = peer;
592
- if (videoConsumer && videoConsumer?.score < videoConsumer?.producerScore) {
593
- allPeersLowQualityConsumersScores.push(videoConsumer.score);
594
- }
595
-
596
- if (audioConsumer && audioConsumer?.score < audioConsumer?.producerScore) {
597
- allPeersLowQualityConsumersScores.push(audioConsumer.score);
598
- }
382
+ peer.getAllConsumers().forEach((item) => {
383
+ if (item.score < item.producerScore) {
384
+ allPeersLowQualityConsumersScores.push(item.score);
385
+ }
386
+ });
599
387
  }, []);
600
388
 
601
389
  if (allPeersLowQualityConsumersScores.length === 0) {
@@ -605,7 +393,7 @@ class Peer {
605
393
  // calculate average score of low quality consumers
606
394
  const scoresSum = allPeersLowQualityConsumersScores.map((score) => score).reduce((acc, curr) => acc + curr, 0);
607
395
  const averageConsumersScore = Math.floor(scoresSum / allPeersLowQualityConsumersScores.length);
608
- this.incomingConnectionQuality = this.getConnectionQualityByScore(averageConsumersScore);
396
+ this.incomingConnectionQuality = Peer.getConnectionQualityByScore(averageConsumersScore);
609
397
  }
610
398
 
611
399
  this.emitConnectionQuality();
@@ -622,18 +410,18 @@ class Peer {
622
410
  return;
623
411
  }
624
412
 
625
- let score = scores[0].score;
413
+ let { score } = scores[0];
626
414
 
627
415
  if (scores.length > 1) {
628
416
  // video with multiple encodings has personal score for each encoding
629
417
  const scoresSum = scores
630
- .map(({ score }) => score)
418
+ .map(({ score: currentScore }) => currentScore)
631
419
  .reduce((acc, curr) => acc + curr, 0);
632
420
 
633
421
  score = Math.floor(scoresSum / payload.scores.length);
634
422
  }
635
423
 
636
- this.outgoingConnectionQuality = this.getConnectionQualityByScore(score);
424
+ this.outgoingConnectionQuality = Peer.getConnectionQualityByScore(score);
637
425
  this.emitConnectionQuality();
638
426
  });
639
427
  }
@@ -647,18 +435,25 @@ class Peer {
647
435
  });
648
436
  }
649
437
 
650
- private getConnectionQualityByScore(score: number): ConnectionQuality {
438
+ static getConnectionQualityByScore(score: number): ConnectionQuality {
651
439
  if (score < ScoreThreshold.BAD) {
652
440
  return ConnectionQuality.BAD;
653
441
  }
654
442
 
655
-
656
443
  if (score < ScoreThreshold.MEDIUM) {
657
444
  return ConnectionQuality.MEDIUM;
658
445
  }
659
446
 
660
447
  return ConnectionQuality.GOOD;
661
448
  }
449
+
450
+ public getAllConsumers(): Consumer[] {
451
+ return Array.from(this.consumers.values());
452
+ }
453
+
454
+ public getAllProducers(): PeerProducer[] {
455
+ return Array.from(this.producers.values());
456
+ }
662
457
  }
663
458
 
664
459
  export default Peer;