@livedigital/client 3.17.0 → 3.18.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.
- package/dist/constants/events.d.ts +3 -0
- package/dist/constants/events.ts +3 -0
- package/dist/engine/Peer.d.ts +14 -3
- package/dist/helpers/peer.d.ts +10 -0
- package/dist/index.es.js +2 -2
- package/dist/index.js +2 -2
- package/dist/types/common.d.ts +12 -0
- package/dist/types/engine.d.ts +4 -0
- package/package.json +1 -1
- package/src/constants/events.ts +3 -0
- package/src/engine/Peer.ts +61 -12
- package/src/engine/handlers/ChannelEventHandler.ts +40 -1
- package/src/helpers/peer.ts +20 -0
- package/src/types/common.ts +16 -0
- package/src/types/engine.ts +5 -0
package/dist/types/common.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ export declare type Role = 'audience' | 'host';
|
|
|
49
49
|
export declare type PeerResponse = {
|
|
50
50
|
id: string;
|
|
51
51
|
channelIds: string[];
|
|
52
|
+
groups: PeerGroup[];
|
|
53
|
+
producePermissions: TrackLabel[];
|
|
52
54
|
appId: string;
|
|
53
55
|
producers: ProducerData[];
|
|
54
56
|
uid?: string;
|
|
@@ -335,3 +337,13 @@ export declare type PeerSyncData = Omit<PeerShortData, 'appData'> & {
|
|
|
335
337
|
appData?: string;
|
|
336
338
|
};
|
|
337
339
|
export declare type TransportAppData = AppData;
|
|
340
|
+
export declare type PeerGroup = 'moderator' | 'user';
|
|
341
|
+
export declare type ChangePeerProducePermissionPayload = {
|
|
342
|
+
peerId: string;
|
|
343
|
+
producePermissions: TrackLabel[];
|
|
344
|
+
};
|
|
345
|
+
export interface ChannelChangeProducePermissionsPayload {
|
|
346
|
+
groups: PeerGroup[];
|
|
347
|
+
producePermissions: TrackLabel[];
|
|
348
|
+
}
|
|
349
|
+
export declare type TrackLabelString = 'camera' | 'microphone' | 'screen-video' | 'screen-audio';
|
package/dist/types/engine.d.ts
CHANGED
|
@@ -78,6 +78,9 @@ export interface ChannelStateInconsistentPayload {
|
|
|
78
78
|
peerId?: string;
|
|
79
79
|
producerId?: string;
|
|
80
80
|
}
|
|
81
|
+
export interface ProducePermissionsChangedPayload {
|
|
82
|
+
labels: TrackLabel[];
|
|
83
|
+
}
|
|
81
84
|
export interface EngineDependenciesFactory {
|
|
82
85
|
createSystem: (params: CreateSystemParams) => System;
|
|
83
86
|
createMedia: (params: CreateMediaParams) => Media;
|
|
@@ -116,6 +119,7 @@ export declare type ClientObserverEvents = {
|
|
|
116
119
|
[CLIENT_EVENTS.forcedDisconnect]: [];
|
|
117
120
|
[CLIENT_EVENTS.rejectUnauthorized]: [];
|
|
118
121
|
[CLIENT_EVENTS.channelStateInconsistent]: [ChannelStateInconsistentPayload];
|
|
122
|
+
[CLIENT_EVENTS.producePermissionsChanged]: [ProducePermissionsChangedPayload];
|
|
119
123
|
};
|
|
120
124
|
export declare type InternalObserverEvents = {
|
|
121
125
|
[INTERNAL_CLIENT_EVENTS.trackProduced]: [Track | BaseTrack];
|
package/package.json
CHANGED
package/src/constants/events.ts
CHANGED
|
@@ -11,6 +11,8 @@ export const CHANNEL_EVENTS = {
|
|
|
11
11
|
getAudioObserverProducer: 'channel.getAudioObserverProducer',
|
|
12
12
|
getGeneralDataProducer: 'channel.getGeneralDataProducer',
|
|
13
13
|
getChannelStateSyncDataProducer: 'channel.getChannelStateSyncDataProducer',
|
|
14
|
+
changeProducePermissions: 'channel.changeProducePermissions',
|
|
15
|
+
changePeerProducePermissions: 'peer.changeProducePermissions',
|
|
14
16
|
ping: 'peer.ping',
|
|
15
17
|
} as const;
|
|
16
18
|
|
|
@@ -32,6 +34,7 @@ export const CLIENT_EVENTS = {
|
|
|
32
34
|
connectionRestored: 'connection-restored',
|
|
33
35
|
forcedDisconnect: 'forced-disconnect',
|
|
34
36
|
rejectUnauthorized: 'reject-unauthorized',
|
|
37
|
+
producePermissionsChanged: 'produce-permissions-changed',
|
|
35
38
|
} as const;
|
|
36
39
|
|
|
37
40
|
export const TRACK_EVENTS = {
|
package/src/engine/Peer.ts
CHANGED
|
@@ -11,19 +11,27 @@ import {
|
|
|
11
11
|
PeerInfo,
|
|
12
12
|
SubscribeOptions,
|
|
13
13
|
PeerShortData,
|
|
14
|
+
PeerGroup,
|
|
15
|
+
TrackLabel, TrackLabelString,
|
|
14
16
|
} from '../types/common';
|
|
15
17
|
import EnhancedEventEmitter from '../EnhancedEventEmitter';
|
|
16
18
|
import Engine from './index';
|
|
17
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
CHANNEL_EVENTS, CLIENT_EVENTS, MEDIASOUP_EVENTS, PEER_EVENTS,
|
|
21
|
+
} from '../constants/events';
|
|
18
22
|
import Logger from './Logger';
|
|
19
23
|
import PeerProducer from './PeerProducer';
|
|
20
24
|
import PeerConsumer from './PeerConsumer';
|
|
21
25
|
import PeerTrack from './media/tracks/PeerTrack';
|
|
22
26
|
import validateAppData from '../helpers/appDataValidator';
|
|
27
|
+
import { ProducePermissionsChangedPayload } from '../types/engine';
|
|
28
|
+
import { logResponse } from '../helpers/peer';
|
|
23
29
|
|
|
24
30
|
interface PeerConstructor {
|
|
25
31
|
id: string;
|
|
26
32
|
channelIds: string[];
|
|
33
|
+
groups: PeerGroup[];
|
|
34
|
+
producePermissions: TrackLabel[];
|
|
27
35
|
appId: string;
|
|
28
36
|
producers: ProducerData[],
|
|
29
37
|
videoConsumer?: PeerConsumer;
|
|
@@ -54,6 +62,7 @@ export type PeerObserverEvents = {
|
|
|
54
62
|
[PEER_EVENTS.trackResumed]: [PeerTrack];
|
|
55
63
|
[PEER_EVENTS.trackPaused]: [PeerTrack];
|
|
56
64
|
[PEER_EVENTS.trackFailed]: [PeerTrack];
|
|
65
|
+
[CLIENT_EVENTS.producePermissionsChanged]: [ProducePermissionsChangedPayload];
|
|
57
66
|
[MEDIASOUP_EVENTS.producerClose]: [ProducerData];
|
|
58
67
|
[MEDIASOUP_EVENTS.newProducer]: [ProducerData];
|
|
59
68
|
[MEDIASOUP_EVENTS.closeConsumer]: [consumerId: string];
|
|
@@ -71,6 +80,10 @@ class Peer {
|
|
|
71
80
|
|
|
72
81
|
public channelIds: string[];
|
|
73
82
|
|
|
83
|
+
public groups: PeerGroup[];
|
|
84
|
+
|
|
85
|
+
public producePermissions: TrackLabel[];
|
|
86
|
+
|
|
74
87
|
public appId: string;
|
|
75
88
|
|
|
76
89
|
public loginDate: Date;
|
|
@@ -100,6 +113,8 @@ class Peer {
|
|
|
100
113
|
constructor({
|
|
101
114
|
id,
|
|
102
115
|
channelIds,
|
|
116
|
+
groups,
|
|
117
|
+
producePermissions,
|
|
103
118
|
appId,
|
|
104
119
|
loginDate,
|
|
105
120
|
producers = [],
|
|
@@ -110,6 +125,8 @@ class Peer {
|
|
|
110
125
|
}: PeerConstructor) {
|
|
111
126
|
this.id = id;
|
|
112
127
|
this.channelIds = channelIds;
|
|
128
|
+
this.groups = groups;
|
|
129
|
+
this.producePermissions = producePermissions;
|
|
113
130
|
this.appId = appId;
|
|
114
131
|
this.loginDate = loginDate;
|
|
115
132
|
this.applicationData = appData || {};
|
|
@@ -136,6 +153,14 @@ class Peer {
|
|
|
136
153
|
return this.id === this.engine.myPeerId;
|
|
137
154
|
}
|
|
138
155
|
|
|
156
|
+
public get isModerator(): boolean {
|
|
157
|
+
return this.groups.includes('moderator');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public get isUser(): boolean {
|
|
161
|
+
return this.groups.includes('user');
|
|
162
|
+
}
|
|
163
|
+
|
|
139
164
|
public get publishedMedia(): PayloadOfPublishedMedia[] {
|
|
140
165
|
return Array.from(this.producers.values()).map((producer) => ({
|
|
141
166
|
producerId: producer.id,
|
|
@@ -156,17 +181,27 @@ class Peer {
|
|
|
156
181
|
};
|
|
157
182
|
}
|
|
158
183
|
|
|
184
|
+
public hasPermission(producePermission: TrackLabel): boolean {
|
|
185
|
+
return this.producePermissions.includes(producePermission);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public hasGroup(group: PeerGroup): boolean {
|
|
189
|
+
return this.groups.includes(group);
|
|
190
|
+
}
|
|
191
|
+
|
|
159
192
|
public async subscribe({ producerId, muted = false }: SubscribeOptions): Promise<void> {
|
|
160
193
|
try {
|
|
161
194
|
const producer = this.producers.get(producerId);
|
|
162
195
|
if (!producer) {
|
|
163
|
-
this.logger.warn('subscribe()',
|
|
196
|
+
this.logger.warn('subscribe()',
|
|
197
|
+
{ message: 'Peer does not have a producer', peer: logResponse(this), producerId });
|
|
164
198
|
return;
|
|
165
199
|
}
|
|
166
200
|
|
|
167
201
|
const peerConsumer = this.getAllConsumers().find((item) => item.producerId === producerId);
|
|
168
202
|
if (peerConsumer) {
|
|
169
|
-
this.logger.debug('subscribe()',
|
|
203
|
+
this.logger.debug('subscribe()',
|
|
204
|
+
{ message: 'Already subscribed to producer', peer: logResponse(this), producerId });
|
|
170
205
|
return;
|
|
171
206
|
}
|
|
172
207
|
|
|
@@ -193,7 +228,7 @@ class Peer {
|
|
|
193
228
|
}
|
|
194
229
|
|
|
195
230
|
this.tracks.set(track.label, track);
|
|
196
|
-
this.logger.debug(`Subscribed for ${producer.kind}`, { peer: this });
|
|
231
|
+
this.logger.debug(`Subscribed for ${producer.kind}`, { peer: logResponse(this) });
|
|
197
232
|
} catch (error) {
|
|
198
233
|
this.logger.error('subscribe()', { producerId, error });
|
|
199
234
|
throw new Error('Error subscribe media');
|
|
@@ -214,13 +249,27 @@ class Peer {
|
|
|
214
249
|
|
|
215
250
|
await track.close();
|
|
216
251
|
this.tracks.delete(track.label);
|
|
217
|
-
this.logger.debug(`Unsubscribed consumer ${consumer.kind}`, { peer: this });
|
|
252
|
+
this.logger.debug(`Unsubscribed consumer ${consumer.kind}`, { peer: logResponse(this) });
|
|
218
253
|
} catch (error) {
|
|
219
254
|
this.logger.error('unsubscribe()', { producerId, error });
|
|
220
255
|
throw new Error('Error unsubscribe media');
|
|
221
256
|
}
|
|
222
257
|
}
|
|
223
258
|
|
|
259
|
+
public async changeProducePermissions(producePermissions: TrackLabelString[]): Promise<void> {
|
|
260
|
+
const isIamModerator = this.engine.peersRepository.get(this.engine.myPeerId ?? '')?.isModerator;
|
|
261
|
+
if (!isIamModerator) {
|
|
262
|
+
throw new Error('Not enough access');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
await this.engine.network.socket.request(CHANNEL_EVENTS.changePeerProducePermissions, {
|
|
266
|
+
peerId: this.id,
|
|
267
|
+
producePermissions,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
this.logger.debug('Produce permissions changed', { peerId: this.id, producePermissions });
|
|
271
|
+
}
|
|
272
|
+
|
|
224
273
|
async getInfo(): Promise<PeerInfo> {
|
|
225
274
|
try {
|
|
226
275
|
return {
|
|
@@ -235,7 +284,7 @@ class Peer {
|
|
|
235
284
|
tracks: await Promise.all(Array.from(this.tracks.values()).map((track) => track.getInfo())),
|
|
236
285
|
};
|
|
237
286
|
} catch (error) {
|
|
238
|
-
this.logger.error('getInfo()', { peer: this, error });
|
|
287
|
+
this.logger.error('getInfo()', { peer: logResponse(this), error });
|
|
239
288
|
throw new Error('Error get info');
|
|
240
289
|
}
|
|
241
290
|
}
|
|
@@ -251,7 +300,7 @@ class Peer {
|
|
|
251
300
|
|
|
252
301
|
const producer = new PeerProducer(producerData);
|
|
253
302
|
this.producers.set(producer.id, producer);
|
|
254
|
-
this.logger.debug('Peer published media:', { peer: this, producer });
|
|
303
|
+
this.logger.debug('Peer published media:', { peer: logResponse(this), producer });
|
|
255
304
|
this.observer.safeEmit(PEER_EVENTS.mediaPublished, {
|
|
256
305
|
producerId: producer.id,
|
|
257
306
|
kind: producer.kind,
|
|
@@ -265,7 +314,7 @@ class Peer {
|
|
|
265
314
|
|
|
266
315
|
this.observer.on(MEDIASOUP_EVENTS.producerClose, async (producer: ProducerData) => {
|
|
267
316
|
this.producers.delete(producer.id);
|
|
268
|
-
this.logger.debug('Peer unpublished media:', { peer: this, producer });
|
|
317
|
+
this.logger.debug('Peer unpublished media:', { peer: logResponse(this), producer });
|
|
269
318
|
this.observer.safeEmit(PEER_EVENTS.mediaUnPublished, {
|
|
270
319
|
producerId: producer.id,
|
|
271
320
|
kind: producer.kind,
|
|
@@ -296,7 +345,7 @@ class Peer {
|
|
|
296
345
|
|
|
297
346
|
await track.close();
|
|
298
347
|
this.tracks.delete(track.label);
|
|
299
|
-
this.logger.debug('Peer video track was ended:', { peer: this, track });
|
|
348
|
+
this.logger.debug('Peer video track was ended:', { peer: logResponse(this), track });
|
|
300
349
|
});
|
|
301
350
|
|
|
302
351
|
this.observer.on(MEDIASOUP_EVENTS.pauseConsumer, async (consumerId) => {
|
|
@@ -464,9 +513,9 @@ class Peer {
|
|
|
464
513
|
validateAppData(appData);
|
|
465
514
|
this.setAppData(appData);
|
|
466
515
|
this.observer.emit(PEER_EVENTS.appDataUpdated, appData);
|
|
467
|
-
this.logger.debug('updatePeerAppData', { peer: this, appData });
|
|
516
|
+
this.logger.debug('updatePeerAppData', { peer: logResponse(this), appData });
|
|
468
517
|
} catch (error) {
|
|
469
|
-
this.logger.error('updatePeerAppData', { peer: this, appData, error });
|
|
518
|
+
this.logger.error('updatePeerAppData', { peer: logResponse(this), appData, error });
|
|
470
519
|
}
|
|
471
520
|
});
|
|
472
521
|
}
|
|
@@ -521,7 +570,7 @@ class Peer {
|
|
|
521
570
|
});
|
|
522
571
|
|
|
523
572
|
this.overallConnectionQuality = connectionQuality;
|
|
524
|
-
this.logger.debug('emitConnectionQuality()', { peer: this, connectionQuality });
|
|
573
|
+
this.logger.debug('emitConnectionQuality()', { peer: logResponse(this), connectionQuality });
|
|
525
574
|
}, 1000);
|
|
526
575
|
}
|
|
527
576
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ActivityConfirmationRequiredPayload,
|
|
2
|
+
ActivityConfirmationRequiredPayload, ChangePeerProducePermissionPayload, ChannelChangeProducePermissionsPayload,
|
|
3
3
|
ChannelEvent,
|
|
4
4
|
LogMessageHandler,
|
|
5
5
|
PeerResponse,
|
|
@@ -78,6 +78,44 @@ class ChannelEventHandler {
|
|
|
78
78
|
this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.activityConfirmationAcquired, event);
|
|
79
79
|
this.logger.info('Notify the channel that the activity has been acquired.', event);
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
connection.on(CHANNEL_EVENTS.changeProducePermissions, (payload: ChannelChangeProducePermissionsPayload) => {
|
|
83
|
+
const { producePermissions, groups } = payload;
|
|
84
|
+
const peers = this.engine.peers.filter((peer) => peer.groups.some((group) => groups.includes(group)));
|
|
85
|
+
peers.forEach((peer) => {
|
|
86
|
+
// eslint-disable-next-line no-param-reassign
|
|
87
|
+
peer.producePermissions = producePermissions;
|
|
88
|
+
|
|
89
|
+
if (!peer.isMe) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.producePermissionsChanged, {
|
|
94
|
+
labels: producePermissions,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
this.logger.info('Peers changed produce permissions', { groups, producePermissions });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
connection.on(CHANNEL_EVENTS.changePeerProducePermissions, (payload: ChangePeerProducePermissionPayload) => {
|
|
102
|
+
const { peerId, producePermissions } = payload;
|
|
103
|
+
const peer = this.engine.peersRepository.get(peerId);
|
|
104
|
+
|
|
105
|
+
if (!peer) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
peer.producePermissions = producePermissions;
|
|
110
|
+
|
|
111
|
+
if (!peer.isMe) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.engine.clientEventEmitter.safeEmit(CLIENT_EVENTS.producePermissionsChanged, {
|
|
116
|
+
labels: producePermissions,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
81
119
|
}
|
|
82
120
|
|
|
83
121
|
private removeEventListeners() {
|
|
@@ -95,6 +133,7 @@ class ChannelEventHandler {
|
|
|
95
133
|
CHANNEL_EVENTS.activityConfirmationExpired,
|
|
96
134
|
CHANNEL_EVENTS.activityConfirmationAcquired,
|
|
97
135
|
CHANNEL_EVENTS.updatePeerAppData,
|
|
136
|
+
CHANNEL_EVENTS.changeProducePermissions,
|
|
98
137
|
];
|
|
99
138
|
|
|
100
139
|
eventNames.forEach((x) => connection.removeAllListeners(x));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Peer from '../engine/Peer';
|
|
2
|
+
|
|
3
|
+
type PeerLogResponse = {
|
|
4
|
+
id: Peer['id'];
|
|
5
|
+
appId: Peer['appId'];
|
|
6
|
+
role: Peer['role'];
|
|
7
|
+
groups: Peer['groups'];
|
|
8
|
+
producePermissions: Peer['producePermissions'];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
12
|
+
export function logResponse(peer: Peer): PeerLogResponse {
|
|
13
|
+
return {
|
|
14
|
+
id: peer.id,
|
|
15
|
+
appId: peer.appId,
|
|
16
|
+
role: peer.role,
|
|
17
|
+
groups: peer.groups,
|
|
18
|
+
producePermissions: peer.producePermissions,
|
|
19
|
+
};
|
|
20
|
+
}
|
package/src/types/common.ts
CHANGED
|
@@ -67,6 +67,8 @@ export type Role = 'audience' | 'host';
|
|
|
67
67
|
export type PeerResponse = {
|
|
68
68
|
id: string,
|
|
69
69
|
channelIds: string[],
|
|
70
|
+
groups: PeerGroup[],
|
|
71
|
+
producePermissions: TrackLabel[],
|
|
70
72
|
appId: string,
|
|
71
73
|
producers: ProducerData[],
|
|
72
74
|
uid?: string,
|
|
@@ -411,3 +413,17 @@ export type PeerSyncData = Omit<PeerShortData, 'appData'> & {
|
|
|
411
413
|
};
|
|
412
414
|
|
|
413
415
|
export type TransportAppData = AppData;
|
|
416
|
+
|
|
417
|
+
export type PeerGroup = 'moderator' | 'user';
|
|
418
|
+
|
|
419
|
+
export type ChangePeerProducePermissionPayload = {
|
|
420
|
+
peerId: string;
|
|
421
|
+
producePermissions: TrackLabel[];
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
export interface ChannelChangeProducePermissionsPayload {
|
|
425
|
+
groups: PeerGroup[];
|
|
426
|
+
producePermissions: TrackLabel[];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export type TrackLabelString = 'camera' | 'microphone' | 'screen-video' | 'screen-audio';
|
package/src/types/engine.ts
CHANGED
|
@@ -107,6 +107,10 @@ export interface ChannelStateInconsistentPayload {
|
|
|
107
107
|
producerId?: string;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
export interface ProducePermissionsChangedPayload {
|
|
111
|
+
labels: TrackLabel[];
|
|
112
|
+
}
|
|
113
|
+
|
|
110
114
|
export interface EngineDependenciesFactory {
|
|
111
115
|
createSystem: (params: CreateSystemParams) => System;
|
|
112
116
|
createMedia: (params: CreateMediaParams) => Media;
|
|
@@ -137,6 +141,7 @@ export type ClientObserverEvents = {
|
|
|
137
141
|
[CLIENT_EVENTS.forcedDisconnect]:[];
|
|
138
142
|
[CLIENT_EVENTS.rejectUnauthorized]:[];
|
|
139
143
|
[CLIENT_EVENTS.channelStateInconsistent]:[ChannelStateInconsistentPayload];
|
|
144
|
+
[CLIENT_EVENTS.producePermissionsChanged]:[ProducePermissionsChangedPayload];
|
|
140
145
|
};
|
|
141
146
|
|
|
142
147
|
export type InternalObserverEvents = {
|