@livedigital/client 2.20.0 → 2.21.0-update-app-data.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.
@@ -236,3 +236,7 @@ export declare enum DeviceErrors {
236
236
  DeviceIsBusy = "DeviceIsBusy",
237
237
  NotAllowedError = "NotAllowedError"
238
238
  }
239
+ export declare type UpdatePeerAppDataPayload = {
240
+ peerId: string;
241
+ appData: Record<string, unknown>;
242
+ };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@livedigital/client",
3
3
  "author": "vlprojects",
4
4
  "license": "MIT",
5
- "version": "2.20.0",
5
+ "version": "2.21.0-update-app-data.1",
6
6
  "private": false,
7
7
  "bugs": {
8
8
  "url": "https://github.com/vlprojects/livedigital-sdk/issues"
@@ -14,3 +14,5 @@ export const LogLevels = {
14
14
 
15
15
  export const CONSUMER_CHECK_STATE_TIMEOUT = 5000;
16
16
  export const PRODUCER_CHECK_STATE_TIMEOUT = 3000;
17
+
18
+ export const PEER_APP_DATA_MAX_SIZE_BYTES = 1024;
@@ -3,6 +3,7 @@ export const CHANNEL_EVENTS = {
3
3
  channelJoin: 'channel.join',
4
4
  channelGetPeers: 'channel.getPeers',
5
5
  channelLeave: 'peer.disconnected',
6
+ updatePeerAppData: 'peer.updateAppData',
6
7
  };
7
8
 
8
9
  export const CLIENT_EVENTS = {
@@ -31,6 +32,7 @@ export const PEER_EVENTS = {
31
32
  trackPaused: 'track-paused',
32
33
  trackResumed: 'track-resumed',
33
34
  trackFailed: 'track-failed',
35
+ appDataUpdated: 'app-data-updated',
34
36
  };
35
37
 
36
38
  export enum SocketIOEvents {
@@ -11,11 +11,12 @@ import {
11
11
  } from '../types/common';
12
12
  import EnhancedEventEmitter from '../EnhancedEventEmitter';
13
13
  import Engine from './index';
14
- import { MEDIASOUP_EVENTS, PEER_EVENTS } from '../constants/events';
14
+ import { CHANNEL_EVENTS, MEDIASOUP_EVENTS, PEER_EVENTS } from '../constants/events';
15
15
  import Logger from './Logger';
16
16
  import PeerProducer from './PeerProducer';
17
17
  import PeerConsumer from './PeerConsumer';
18
18
  import PeerTrack from './media/tracks/PeerTrack';
19
+ import validateAppData from '../helpers/appDataValidator';
19
20
 
20
21
  interface PeerConstructor {
21
22
  id: string;
@@ -49,7 +50,7 @@ class Peer {
49
50
 
50
51
  public uid?: string;
51
52
 
52
- public appData: Record<string, unknown>;
53
+ private applicationData: Record<string, unknown>;
53
54
 
54
55
  public role: Role;
55
56
 
@@ -84,7 +85,7 @@ class Peer {
84
85
  this.channelIds = channelIds;
85
86
  this.appId = appId;
86
87
  this.loginDate = loginDate;
87
- this.appData = appData || {};
88
+ this.applicationData = appData || {};
88
89
  this.uid = uid;
89
90
  this.role = role;
90
91
  this.engine = engine;
@@ -96,6 +97,10 @@ class Peer {
96
97
  this.handlePeerEvents();
97
98
  }
98
99
 
100
+ get appData(): Record<string, unknown> {
101
+ return this.applicationData;
102
+ }
103
+
99
104
  get observer(): EnhancedEventEmitter {
100
105
  return this._observer;
101
106
  }
@@ -353,6 +358,17 @@ class Peer {
353
358
  spatialLayer,
354
359
  });
355
360
  });
361
+
362
+ this.observer.on(CHANNEL_EVENTS.updatePeerAppData, (appData: Record<string, unknown>) => {
363
+ try {
364
+ validateAppData(appData);
365
+ this.setAppData(appData);
366
+ this.observer.emit(PEER_EVENTS.appDataUpdated, appData);
367
+ this.logger.debug('updatePeerAppData', { peer: this, appData });
368
+ } catch (error) {
369
+ this.logger.error('updatePeerAppData', { peer: this, appData, error });
370
+ }
371
+ });
356
372
  }
357
373
 
358
374
  private emitConnectionQuality(): void {
@@ -402,6 +418,10 @@ class Peer {
402
418
  private getTrackByConsumerId(id: string): PeerTrack | undefined {
403
419
  return Array.from(this.tracks.values()).find((track) => track.consumerId === id);
404
420
  }
421
+
422
+ private setAppData(appData: Record<string, unknown>) {
423
+ this.applicationData = appData;
424
+ }
405
425
  }
406
426
 
407
427
  export default Peer;
@@ -1,4 +1,4 @@
1
- import { ChannelEvent, PeerResponse } from '../../types/common';
1
+ import { ChannelEvent, PeerResponse, UpdatePeerAppDataPayload } from '../../types/common';
2
2
  import Engine from '../index';
3
3
  import { CHANNEL_EVENTS, CLIENT_EVENTS } from '../../constants/events';
4
4
  import Logger from '../Logger';
@@ -39,6 +39,15 @@ class ChannelEventHandler {
39
39
  this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.peerLeft, peerId);
40
40
  this.logger.debug('Peer left the channel', { peerId });
41
41
  });
42
+
43
+ connection.on(CHANNEL_EVENTS.updatePeerAppData, ({ peerId, appData }: UpdatePeerAppDataPayload) => {
44
+ const peer = this.engine.peers.find((item) => item.id === peerId);
45
+ if (!peer) {
46
+ return;
47
+ }
48
+
49
+ peer.observer.emit(CHANNEL_EVENTS.updatePeerAppData, appData);
50
+ });
42
51
  }
43
52
  }
44
53
 
@@ -31,6 +31,7 @@ import { retryAsync } from '../helpers/retry';
31
31
  import { EngineDependenciesFactory, IssuesHandler } from '../types/engine';
32
32
  import { LogLevels } from '../constants/common';
33
33
  import { LoadBalancerApiClientParams } from './network/LoadBalancerClient';
34
+ import validateAppData from '../helpers/appDataValidator';
34
35
 
35
36
  type EngineParams = {
36
37
  clientEventEmitter: EnhancedEventEmitter,
@@ -220,6 +221,21 @@ class Engine {
220
221
  this.peersRepository.delete(peerId);
221
222
  }
222
223
 
224
+ public async updateAppData(appData: Record<string, unknown>): Promise<void> {
225
+ const { myPeer } = this;
226
+ if (!myPeer) {
227
+ throw new Error('Need join to channel first');
228
+ }
229
+
230
+ try {
231
+ validateAppData(appData);
232
+ await this.network.updatePeerAppData({ peerId: myPeer.id, appData });
233
+ } catch (error) {
234
+ this.logger.error('updateAppData()', { error });
235
+ throw new Error('Can not update peer appData');
236
+ }
237
+ }
238
+
223
239
  async createCameraVideoTrack(options?: CreateCameraVideoTrackOptions): Promise<Track> {
224
240
  const trackParams = Media.getCameraVideoTrackParams(options);
225
241
  try {
@@ -140,7 +140,7 @@ class BaseTrack {
140
140
 
141
141
  private async checkProducerState(): Promise<void> {
142
142
  try {
143
- if (this.#closed) {
143
+ if (this.#closed || this.kind === 'audio') {
144
144
  return;
145
145
  }
146
146
 
@@ -149,6 +149,7 @@ class BaseTrack {
149
149
 
150
150
  const isCodecsMatched = await this.isCodecsMatched();
151
151
  if (this.#producerRestarted && !isCodecsMatched) {
152
+ await this.closeSelfConsumer();
152
153
  this.clientEventEmitter.emit(CLIENT_EVENTS.trackPublishingFailed, this);
153
154
  this.logger.debug('trackPublishingFail()', { track: this });
154
155
  return;
@@ -1,3 +1,4 @@
1
+ import { MediaKind } from 'mediasoup-client/lib/types';
1
2
  import {
2
3
  PreferredLayersParams, SetConsumerPriorityParams,
3
4
  SpatialLayerParams,
@@ -59,6 +60,10 @@ class PeerTrack {
59
60
  return this.#mediaStreamTrack;
60
61
  }
61
62
 
63
+ get kind(): MediaKind {
64
+ return this.mediaStreamTrack.kind as MediaKind;
65
+ }
66
+
62
67
  get isPaused(): boolean {
63
68
  return this.#paused;
64
69
  }
@@ -252,7 +257,7 @@ class PeerTrack {
252
257
 
253
258
  private async checkConsumerState(): Promise<void> {
254
259
  try {
255
- if (this.#closed) {
260
+ if (this.#closed || this.kind === 'audio') {
256
261
  return;
257
262
  }
258
263
 
@@ -8,10 +8,10 @@ import { Device } from 'mediasoup-client';
8
8
  import { Consumer } from 'mediasoup-client/lib/Consumer';
9
9
  import SocketIO from './Socket';
10
10
  import {
11
- CreateConsumerPayload, LogLevel, ProduceParams, RemoteConsumerOptions, SocketResponse,
11
+ CreateConsumerPayload, LogLevel, ProduceParams, RemoteConsumerOptions, SocketResponse, UpdatePeerAppDataPayload,
12
12
  } from '../../types/common';
13
13
  import LoadBalancerApiClient from './LoadBalancerClient';
14
- import { MEDIASOUP_EVENTS, MEDIASOUP_TRANSPORT_EVENTS } from '../../constants/events';
14
+ import { CHANNEL_EVENTS, MEDIASOUP_EVENTS, MEDIASOUP_TRANSPORT_EVENTS } from '../../constants/events';
15
15
  import Logger from '../Logger';
16
16
 
17
17
  export type NetworkParams = {
@@ -264,6 +264,10 @@ class Network {
264
264
  async pauseRemoteConsumer(consumerId: string): Promise<SocketResponse> {
265
265
  return this.socket.request(MEDIASOUP_EVENTS.pauseConsumer, { consumerId });
266
266
  }
267
+
268
+ async updatePeerAppData({ peerId, appData }: UpdatePeerAppDataPayload): Promise<SocketResponse> {
269
+ return this.socket.request(CHANNEL_EVENTS.updatePeerAppData, { peerId, appData });
270
+ }
267
271
  }
268
272
 
269
273
  export default Network;
@@ -0,0 +1,19 @@
1
+ import { PEER_APP_DATA_MAX_SIZE_BYTES } from '../constants/common';
2
+
3
+ const validateAppData = (appData: Record<string, unknown>): void => {
4
+ let validStringifiesJsonAppData;
5
+ try {
6
+ validStringifiesJsonAppData = JSON.stringify(appData);
7
+ } catch (err) {
8
+ throw new Error('Invalid appData');
9
+ }
10
+
11
+ const size = new TextEncoder().encode(validStringifiesJsonAppData).length;
12
+ if (size <= PEER_APP_DATA_MAX_SIZE_BYTES) {
13
+ return;
14
+ }
15
+
16
+ throw new Error('Maximum size appData reached');
17
+ };
18
+
19
+ export default validateAppData;
package/src/index.ts CHANGED
@@ -112,6 +112,10 @@ class Client {
112
112
  loadPeers(role?: Role): Promise<void> {
113
113
  return this.engine.loadPeers(role);
114
114
  }
115
+
116
+ updateAppData(appData: Record<string, unknown>): Promise<void> {
117
+ return this.engine.updateAppData(appData);
118
+ }
115
119
  }
116
120
 
117
121
  export default Client;
@@ -273,3 +273,8 @@ export enum DeviceErrors {
273
273
  DeviceIsBusy = 'DeviceIsBusy',
274
274
  NotAllowedError = 'NotAllowedError',
275
275
  }
276
+
277
+ export type UpdatePeerAppDataPayload = {
278
+ peerId: string,
279
+ appData: Record<string, unknown>,
280
+ };