@livedigital/client 1.1.5 → 1.4.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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@livedigital/client",
3
3
  "author": "vlprojects",
4
4
  "license": "MIT",
5
- "version": "1.1.5",
5
+ "version": "1.4.1",
6
6
  "private": false,
7
7
  "bugs": {
8
8
  "url": "https://github.com/vlprojects/livedigital-sdk/issues"
@@ -45,22 +45,21 @@
45
45
  "mediasoup-client": "^3.6.42",
46
46
  "qs": "^6.9.6",
47
47
  "serialize-error": "^7.0.1",
48
- "socket.io-client": "^4.2.0"
48
+ "socket.io-client": "^4.3.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@rollup/plugin-commonjs": "^19.0.0",
52
52
  "@rollup/plugin-json": "^4.1.0",
53
53
  "@rollup/plugin-node-resolve": "^13.0.0",
54
54
  "@rollup/plugin-replace": "^3.0.0",
55
- "@types/node": "^12.0.0",
56
- "@types/qs": "^6.9.5",
57
- "@types/socket.io-client": "^1.4.34",
58
- "@typescript-eslint/eslint-plugin": "^4.23.0",
59
55
  "@semantic-release/commit-analyzer": "^9.0.1",
60
56
  "@semantic-release/git": "^10.0.0",
61
57
  "@semantic-release/github": "^8.0.1",
62
58
  "@semantic-release/npm": "^8.0.0",
63
59
  "@semantic-release/release-notes-generator": "^10.0.2",
60
+ "@types/node": "^12.0.0",
61
+ "@types/qs": "^6.9.5",
62
+ "@typescript-eslint/eslint-plugin": "^4.23.0",
64
63
  "dotenv": "^10.0.0",
65
64
  "eslint": "^7.23.0",
66
65
  "eslint-config-airbnb-typescript": "^12.3.1",
@@ -7,8 +7,10 @@ export const CHANNEL_EVENTS = {
7
7
 
8
8
  export const CLIENT_EVENTS = {
9
9
  channelEvent: 'channel-event',
10
- channelJoin: 'peer-joined',
10
+ peerJoined: 'peer-joined',
11
+ peerLeft: 'peer-left',
11
12
  channelLeave: 'peer-left',
13
+ channelRejoinRequired: 'channel-rejoin-required',
12
14
  };
13
15
 
14
16
  export const PEER_EVENTS = {
@@ -47,7 +47,7 @@ class Peer {
47
47
 
48
48
  public uid?: string;
49
49
 
50
- public appData = {};
50
+ public appData: Record<string, unknown>;
51
51
 
52
52
  private videoProducer?: ProducerData;
53
53
 
@@ -75,7 +75,8 @@ class Peer {
75
75
  videoConsumer,
76
76
  audioConsumer,
77
77
  engine,
78
- appData = {},
78
+ appData,
79
+ uid,
79
80
  }: PeerConstructor) {
80
81
  this.id = id;
81
82
  this.channelId = channelId;
@@ -84,7 +85,8 @@ class Peer {
84
85
  this.isVirtual = isVirtual;
85
86
  this.originChannelId = originChannelId;
86
87
  this.originPeerId = originPeerId;
87
- this.appData = appData;
88
+ this.appData = appData || {};
89
+ this.uid = uid;
88
90
  this.engine = engine;
89
91
  this.videoConsumer = videoConsumer;
90
92
  this.audioConsumer = audioConsumer;
@@ -159,11 +161,13 @@ class Peer {
159
161
 
160
162
  public async subscribeVideo(): Promise<void> {
161
163
  if (!this.videoProducer) {
162
- throw new Error('Video producer not found');
164
+ this.logger.warn('subscribeVideo()', { message: 'This peer has no published video', peer: this });
165
+ return;
163
166
  }
164
167
 
165
168
  if (this.videoConsumer) {
166
- throw new Error('Already subscribed');
169
+ this.logger.warn('subscribeVideo()', { message: 'Already subscribed this peer\'s video', peer: this });
170
+ return;
167
171
  }
168
172
 
169
173
  await this.createConsumer(this.videoProducer);
@@ -171,11 +175,13 @@ class Peer {
171
175
 
172
176
  public async subscribeAudio(): Promise<void> {
173
177
  if (!this.audioProducer) {
174
- throw new Error('Audio producer not found');
178
+ this.logger.warn('subscribeAudio()', { message: 'This peer has no published audio', peer: this });
179
+ return;
175
180
  }
176
181
 
177
182
  if (this.audioConsumer) {
178
- throw new Error('Already subscribed');
183
+ this.logger.warn('subscribeAudio()', { message: 'Already subscribed this peer\'s audio', peer: this });
184
+ return;
179
185
  }
180
186
 
181
187
  await this.createConsumer(this.audioProducer);
@@ -183,6 +189,7 @@ class Peer {
183
189
 
184
190
  public async unSubscribeVideo(): Promise<void> {
185
191
  if (!this.videoConsumer) {
192
+ this.logger.warn('unSubscribeVideo()', { message: 'This peer has no subscribed video', peer: this });
186
193
  return;
187
194
  }
188
195
 
@@ -193,6 +200,7 @@ class Peer {
193
200
 
194
201
  public async unSubscribeAudio(): Promise<void> {
195
202
  if (!this.audioConsumer) {
203
+ this.logger.warn('unSubscribeAudio()', { message: 'This peer has no subscribed audio', peer: this });
196
204
  return;
197
205
  }
198
206
 
@@ -236,52 +244,79 @@ class Peer {
236
244
  }
237
245
 
238
246
  public async pauseVideo(): Promise<void> {
239
- if (!this.videoConsumer || this.videoConsumer.paused) {
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 });
240
254
  return;
241
255
  }
242
256
 
243
257
  try {
244
258
  await this.pauseRemoteConsumer(this.videoConsumer?.id);
245
259
  this.videoConsumer.pause();
260
+ this.logger.debug('pauseVideo()', { peer: this });
246
261
  } catch (err) {
247
262
  this.logger.error('pauseVideo()', err);
248
263
  }
249
264
  }
250
265
 
251
266
  public async pauseAudio(): Promise<void> {
252
- if (!this.audioConsumer || this.audioConsumer.paused) {
267
+ if (!this.audioConsumer) {
268
+ this.logger.warn('pauseAudio()', { message: 'This peer has no subscribed audio', peer: this });
269
+ return;
270
+ }
271
+
272
+ if (this.audioConsumer.paused) {
273
+ this.logger.warn('pauseAudio()', { message: 'Already paused', peer: this });
253
274
  return;
254
275
  }
255
276
 
256
277
  try {
257
278
  await this.pauseRemoteConsumer(this.audioConsumer?.id);
258
279
  this.audioConsumer.pause();
280
+ this.logger.debug('pauseAudio()', { peer: this });
259
281
  } catch (err) {
260
282
  this.logger.error('pauseAudio()', err);
261
283
  }
262
284
  }
263
285
 
264
286
  public async resumeVideo(): Promise<void> {
265
- if (!this.videoConsumer || !this.videoConsumer.paused) {
287
+ if (!this.videoConsumer) {
288
+ this.logger.warn('resumeVideo()', { message: 'This peer has no subscribed video', peer: this });
289
+ return;
290
+ }
291
+
292
+ if (!this.videoConsumer.paused) {
293
+ this.logger.warn('resumeVideo()', { message: 'Video is not paused', peer: this });
266
294
  return;
267
295
  }
268
296
 
269
297
  try {
270
298
  await this.resumeRemoteConsumer(this.videoConsumer?.id);
271
299
  this.videoConsumer.resume();
300
+ this.logger.debug('resumeVideo()', { peer: this });
272
301
  } catch (err) {
273
302
  this.logger.error('resumeVideo()', err);
274
303
  }
275
304
  }
276
305
 
277
306
  public async resumeAudio(): Promise<void> {
278
- if (!this.audioConsumer || !this.audioConsumer.paused) {
307
+ if (!this.audioConsumer) {
308
+ this.logger.warn('resumeAudio()', { message: 'This peer has no subscribed audio', peer: this });
279
309
  return;
280
310
  }
281
311
 
312
+ if (this.audioConsumer.paused) {
313
+ this.logger.warn('resumeAudio()', { message: 'Audio is not paused', peer: this });
314
+ return;
315
+ }
282
316
  try {
283
317
  await this.resumeRemoteConsumer(this.audioConsumer?.id);
284
318
  this.audioConsumer.resume();
319
+ this.logger.debug('resumeAudio()', { peer: this });
285
320
  } catch (err) {
286
321
  this.logger.error('resumeAudio()', err);
287
322
  }
@@ -289,6 +324,7 @@ class Peer {
289
324
 
290
325
  public async setVideoStreamPriority(priority: number): Promise<void> {
291
326
  if (!this.videoConsumer) {
327
+ this.logger.warn('setVideoStreamPriority()', { message: 'This peer has no subscribed audio', peer: this });
292
328
  return;
293
329
  }
294
330
 
@@ -297,6 +333,7 @@ class Peer {
297
333
 
298
334
  public async setAudioStreamPriority(priority: number): Promise<void> {
299
335
  if (!this.audioConsumer) {
336
+ this.logger.warn('setAudioStreamPriority()', { message: 'This peer has no subscribed audio', peer: this });
300
337
  return;
301
338
  }
302
339
 
@@ -306,7 +343,9 @@ class Peer {
306
343
  private async setConsumerPriority(params: SetConsumerPriorityParams): Promise<void> {
307
344
  try {
308
345
  await this.engine.network.socket.request(MEDIASOUP_EVENTS.setConsumerPriority, params);
346
+ this.logger.debug('setConsumerPriority()', { peer: this, params });
309
347
  } catch (err) {
348
+ this.logger.error('setConsumerPriority()', { peer: this, params });
310
349
  throw new Error('Can`t change stream priority');
311
350
  }
312
351
  }
@@ -340,6 +379,7 @@ class Peer {
340
379
  this.videoConsumer = new VideoConsumer(consumer);
341
380
  }
342
381
 
382
+ this.logger.debug(`Subscribed for ${producer.kind}`, { peer: this });
343
383
  this.observer.safeEmit(PEER_EVENTS.trackStart, { kind: producer.kind, track: consumer.track });
344
384
  } catch (error) {
345
385
  this.logger.error('createConsumer()', producer, error);
@@ -355,9 +395,10 @@ class Peer {
355
395
  });
356
396
 
357
397
  consumer.close();
398
+ this.logger.warn('Unsubscribed media', { peer: this, kind: consumer.kind });
358
399
  } catch (err) {
359
- this.logger.error('closeConsumer()', consumer, err);
360
- throw new Error('Error subscribe media');
400
+ this.logger.debug('closeConsumer()', { peer: this, consumer, error: err });
401
+ throw new Error('Error unsubscribe media');
361
402
  }
362
403
  }
363
404
 
@@ -383,8 +424,12 @@ class Peer {
383
424
  temporalLayer,
384
425
  });
385
426
  } catch (err) {
386
- this.logger.error('changeConsumerPreferredLayers()', { consumerId: this.videoConsumer.id });
387
- throw new Error('Error subscribe media');
427
+ this.logger.error('changeConsumerPreferredLayers()', {
428
+ peer: this,
429
+ consumer: this.videoConsumer,
430
+ error: err,
431
+ });
432
+ throw new Error('Error change preferred layer');
388
433
  }
389
434
  }
390
435
 
@@ -440,10 +485,11 @@ class Peer {
440
485
  if (producer.kind === ProducerKind.VIDEO) {
441
486
  this.setVideoProducer(producer);
442
487
  } else {
443
- this.setVideoProducer(producer);
488
+ this.setAudioProducer(producer);
444
489
  }
445
490
 
446
- this.engine.clientEventEmitter.safeEmit(PEER_EVENTS.mediaPublished, { kind: producer.kind });
491
+ this.logger.debug('Peer published media:', { peer: this, producer });
492
+ this.observer.safeEmit(PEER_EVENTS.mediaPublished, { kind: producer.kind });
447
493
  });
448
494
 
449
495
  this.observer.on(MEDIASOUP_EVENTS.producerClose, (producer: ProducerData) => {
@@ -453,28 +499,50 @@ class Peer {
453
499
  this.removeAudioProducer();
454
500
  }
455
501
 
456
- this.engine.clientEventEmitter.safeEmit(PEER_EVENTS.mediaUnPublished, { kind: producer.kind });
502
+ this.logger.debug('Peer unpublished media:', { peer: this, producer });
503
+ this.observer.safeEmit(PEER_EVENTS.mediaUnPublished, { kind: producer.kind });
504
+ });
505
+
506
+ this.observer.on(MEDIASOUP_EVENTS.closeConsumer, (consumerId) => {
507
+ if (this.videoConsumer?.id === consumerId) {
508
+ this.videoConsumer?.close();
509
+ this.videoConsumer = undefined;
510
+ this.observer.safeEmit(PEER_EVENTS.trackEnd, { kind: 'video' });
511
+ this.logger.debug('Peer video track was ended:', { peer: this });
512
+ return;
513
+ }
514
+
515
+ if (this.audioConsumer?.id === consumerId) {
516
+ this.audioConsumer?.close();
517
+ this.audioConsumer = undefined;
518
+ this.logger.debug('Peer audio track was ended:', { peer: this });
519
+ this.observer.safeEmit(PEER_EVENTS.trackEnd, { kind: 'audio' });
520
+ }
457
521
  });
458
522
 
459
523
  this.observer.on(MEDIASOUP_EVENTS.pauseConsumer, (consumerId) => {
460
524
  if (this.videoConsumer?.id === consumerId) {
461
525
  this.videoConsumer?.pause();
526
+ this.logger.debug('Peer video track was paused:', { peer: this });
462
527
  return;
463
528
  }
464
529
 
465
530
  if (this.audioConsumer?.id === consumerId) {
466
531
  this.audioConsumer?.pause();
532
+ this.logger.debug('Peer audio track was paused:', { peer: this });
467
533
  }
468
534
  });
469
535
 
470
536
  this.observer.on(MEDIASOUP_EVENTS.resumeConsumer, (consumerId) => {
471
537
  if (this.videoConsumer?.id === consumerId) {
472
538
  this.videoConsumer?.resume();
539
+ this.logger.debug('Peer video track was resumed:', { peer: this });
473
540
  return;
474
541
  }
475
542
 
476
543
  if (this.audioConsumer?.id === consumerId) {
477
544
  this.audioConsumer?.resume();
545
+ this.logger.debug('Peer video track was resumed:', { peer: this });
478
546
  }
479
547
  });
480
548
 
@@ -487,6 +555,11 @@ class Peer {
487
555
 
488
556
  this.videoConsumer.setCurrentSpatialLayer(spatialLayer);
489
557
  this.videoConsumer.setCurrentTemporalLayer(temporalLayer);
558
+ this.logger.debug('Peer video track was changed preferred layers:', {
559
+ peer: this,
560
+ spatialLayer,
561
+ temporalLayer,
562
+ });
490
563
  });
491
564
  }
492
565
  }
@@ -1,22 +1,28 @@
1
1
  import { ChannelEvent, PeerResponse } from '../../types/common';
2
2
  import Engine from '../index';
3
3
  import { CHANNEL_EVENTS, CLIENT_EVENTS } from '../../constants/events';
4
+ import Logger from '../Logger';
4
5
 
5
6
  class ChannelEventHandler {
6
7
  private readonly engine: Engine;
7
8
 
9
+ private readonly logger: Logger;
10
+
8
11
  constructor(engine: Engine) {
9
12
  this.engine = engine;
13
+ this.logger = new Logger('ChannelEvents');
10
14
  }
11
15
 
12
16
  public subscribeToEvents(): void {
13
17
  const { connection } = this.engine.network.socket;
14
18
  if (!connection) {
19
+ this.logger.error('subscribeToEvents()', { error: 'Socket connection not initialized' });
15
20
  throw new Error('Socket connection not initialized');
16
21
  }
17
22
 
18
23
  connection.on(CHANNEL_EVENTS.channelEvent, (event: ChannelEvent) => {
19
24
  this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.channelEvent, event);
25
+ this.logger.debug('New channel event', { event });
20
26
  });
21
27
 
22
28
  connection.on(CHANNEL_EVENTS.channelJoin, (peerData: PeerResponse) => {
@@ -26,22 +32,16 @@ class ChannelEventHandler {
26
32
  return;
27
33
  }
28
34
 
29
- this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.channelJoin, peer);
35
+ this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.peerJoined, peer);
36
+ this.logger.debug('Peer joined to the channel', { peer });
30
37
  });
31
38
 
32
39
  connection.on(CHANNEL_EVENTS.channelLeave, (peerId: string) => {
33
40
  this.engine.removePeer(peerId);
34
- this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.channelLeave, peerId);
41
+ this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.peerLeft, peerId);
42
+ this.logger.debug('Peer left the channel', { peerId });
35
43
  });
36
44
  }
37
-
38
- public unsubscribeEvents(): void {
39
- this.removeEventListeners(Object.values(CHANNEL_EVENTS));
40
- }
41
-
42
- private removeEventListeners(events: string[]): void {
43
- events.forEach((event) => this.engine.network.socket.connection?.removeEventListener(event));
44
- }
45
45
  }
46
46
 
47
47
  export default ChannelEventHandler;
@@ -1,17 +1,22 @@
1
1
  import { ChangePreferredLayersParams, ProducerData } from '../../types/common';
2
2
  import Engine from '../index';
3
3
  import { MEDIASOUP_EVENTS } from '../../constants/events';
4
+ import Logger from '../Logger';
4
5
 
5
6
  class MediaSoupEventHandler {
6
7
  private readonly engine: Engine;
7
8
 
9
+ private readonly logger: Logger;
10
+
8
11
  constructor(engine: Engine) {
9
12
  this.engine = engine;
13
+ this.logger = new Logger('MediasoupEvents');
10
14
  }
11
15
 
12
16
  public subscribeToEvents(): void {
13
17
  const { connection } = this.engine.network.socket;
14
18
  if (!connection) {
19
+ this.logger.error('subscribeToEvents()', { error: 'Socket connection not initialized' });
15
20
  throw new Error('Socket connection not initialized');
16
21
  }
17
22
 
@@ -33,6 +38,15 @@ class MediaSoupEventHandler {
33
38
  peer.observer.safeEmit(MEDIASOUP_EVENTS.newProducer, producer);
34
39
  });
35
40
 
41
+ connection.on(MEDIASOUP_EVENTS.closeConsumer, (consumerId: string, peerId: string) => {
42
+ const peer = this.engine.peers.find((item) => item.id === peerId);
43
+ if (!peer) {
44
+ return;
45
+ }
46
+
47
+ peer.observer.safeEmit(MEDIASOUP_EVENTS.closeConsumer, consumerId);
48
+ });
49
+
36
50
  connection.on(MEDIASOUP_EVENTS.resumeConsumer, (consumerId: string, peerId: string) => {
37
51
  const peer = this.engine.peers.find((item) => item.id === peerId);
38
52
  if (!peer || peer.isMe) {
@@ -65,14 +79,6 @@ class MediaSoupEventHandler {
65
79
  });
66
80
  });
67
81
  }
68
-
69
- public unsubscribeEvents(): void {
70
- this.removeEventListeners(Object.values(MEDIASOUP_EVENTS));
71
- }
72
-
73
- private removeEventListeners(events: string[]): void {
74
- events.forEach((event) => this.engine.network.socket.connection?.removeEventListener(event));
75
- }
76
82
  }
77
83
 
78
84
  export default MediaSoupEventHandler;