@fishjam-cloud/ts-client 0.5.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.
Files changed (52) hide show
  1. package/README.md +134 -0
  2. package/dist/src/FishjamClient.d.ts +523 -0
  3. package/dist/src/FishjamClient.js +666 -0
  4. package/dist/src/auth.d.ts +3 -0
  5. package/dist/src/auth.js +8 -0
  6. package/dist/src/index.d.ts +7 -0
  7. package/dist/src/index.js +3 -0
  8. package/dist/src/protos/fishjam/peer_notifications.d.ts +78 -0
  9. package/dist/src/protos/fishjam/peer_notifications.js +302 -0
  10. package/dist/src/protos/index.d.ts +1 -0
  11. package/dist/src/protos/index.js +1 -0
  12. package/dist/src/reconnection.d.ts +27 -0
  13. package/dist/src/reconnection.js +121 -0
  14. package/dist/src/webrtc/CommandsQueue.d.ts +23 -0
  15. package/dist/src/webrtc/CommandsQueue.js +102 -0
  16. package/dist/src/webrtc/ConnectionManager.d.ts +29 -0
  17. package/dist/src/webrtc/ConnectionManager.js +82 -0
  18. package/dist/src/webrtc/bitrate.d.ts +12 -0
  19. package/dist/src/webrtc/bitrate.js +12 -0
  20. package/dist/src/webrtc/deferred.d.ts +8 -0
  21. package/dist/src/webrtc/deferred.js +17 -0
  22. package/dist/src/webrtc/index.d.ts +3 -0
  23. package/dist/src/webrtc/index.js +1 -0
  24. package/dist/src/webrtc/internal.d.ts +26 -0
  25. package/dist/src/webrtc/internal.js +34 -0
  26. package/dist/src/webrtc/mediaEvent.d.ts +10 -0
  27. package/dist/src/webrtc/mediaEvent.js +16 -0
  28. package/dist/src/webrtc/tracks/Local.d.ts +51 -0
  29. package/dist/src/webrtc/tracks/Local.js +289 -0
  30. package/dist/src/webrtc/tracks/LocalTrack.d.ts +62 -0
  31. package/dist/src/webrtc/tracks/LocalTrack.js +235 -0
  32. package/dist/src/webrtc/tracks/LocalTrackManager.d.ts +38 -0
  33. package/dist/src/webrtc/tracks/LocalTrackManager.js +83 -0
  34. package/dist/src/webrtc/tracks/Remote.d.ts +38 -0
  35. package/dist/src/webrtc/tracks/Remote.js +200 -0
  36. package/dist/src/webrtc/tracks/RemoteTrack.d.ts +39 -0
  37. package/dist/src/webrtc/tracks/RemoteTrack.js +64 -0
  38. package/dist/src/webrtc/tracks/TrackCommon.d.ts +8 -0
  39. package/dist/src/webrtc/tracks/TrackCommon.js +1 -0
  40. package/dist/src/webrtc/tracks/bandwidth.d.ts +1 -0
  41. package/dist/src/webrtc/tracks/bandwidth.js +27 -0
  42. package/dist/src/webrtc/tracks/encodings.d.ts +1 -0
  43. package/dist/src/webrtc/tracks/encodings.js +7 -0
  44. package/dist/src/webrtc/tracks/transceivers.d.ts +2 -0
  45. package/dist/src/webrtc/tracks/transceivers.js +78 -0
  46. package/dist/src/webrtc/types.d.ts +306 -0
  47. package/dist/src/webrtc/types.js +2 -0
  48. package/dist/src/webrtc/voiceActivityDetection.d.ts +2 -0
  49. package/dist/src/webrtc/voiceActivityDetection.js +2 -0
  50. package/dist/src/webrtc/webRTCEndpoint.d.ts +299 -0
  51. package/dist/src/webrtc/webRTCEndpoint.js +730 -0
  52. package/package.json +82 -0
@@ -0,0 +1,666 @@
1
+ import { WebRTCEndpoint } from './webrtc';
2
+ import { EventEmitter } from 'events';
3
+ import { PeerMessage } from './protos';
4
+ import { ReconnectManager } from './reconnection';
5
+ import { isAuthError } from './auth';
6
+ const STATISTICS_INTERVAL = 10_000;
7
+ const isPeer = (endpoint) => endpoint.type === 'webrtc';
8
+ const isComponent = (endpoint) => endpoint.type === 'recording' ||
9
+ endpoint.type === 'hls' ||
10
+ endpoint.type === 'file' ||
11
+ endpoint.type === 'rtsp' ||
12
+ endpoint.type === 'sip';
13
+ /**
14
+ * FishjamClient is the main class to interact with Fishjam.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const client = new FishjamClient<PeerMetadata, TrackMetadata>();
19
+ * const peerToken = "YOUR_PEER_TOKEN";
20
+ *
21
+ * // You can listen to events emitted by the client
22
+ * client.on("joined", (peerId, peersInRoom) => {
23
+ * console.log("join success");
24
+ * });
25
+ *
26
+ * // Start the peer connection
27
+ * client.connect({
28
+ * peerMetadata: {},
29
+ * isSimulcastOn: false,
30
+ * token: peerToken
31
+ * });
32
+ *
33
+ * // Close the peer connection
34
+ * client.disconnect();
35
+ * ```
36
+ *
37
+ * You can register callbacks to handle the events emitted by the Client.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ *
42
+ * client.on("trackReady", (ctx) => {
43
+ * console.log("On track ready");
44
+ * });
45
+ * ```
46
+ */
47
+ export class FishjamClient extends EventEmitter {
48
+ websocket = null;
49
+ webrtc = null;
50
+ removeEventListeners = null;
51
+ status = 'new';
52
+ connectConfig = null;
53
+ reconnectManager;
54
+ sendStatisticsInterval = undefined;
55
+ peerMetadataParser;
56
+ trackMetadataParser;
57
+ constructor(config) {
58
+ super();
59
+ this.peerMetadataParser =
60
+ config?.peerMetadataParser ?? ((x) => x);
61
+ this.trackMetadataParser =
62
+ config?.trackMetadataParser ?? ((x) => x);
63
+ this.reconnectManager = new ReconnectManager(this, (peerMetadata) => this.initConnection(peerMetadata), config?.reconnect);
64
+ }
65
+ /**
66
+ * Uses the {@link !WebSocket} connection and {@link !WebRTCEndpoint | WebRTCEndpoint} to join to the room. Registers the callbacks to
67
+ * handle the events emitted by the {@link !WebRTCEndpoint | WebRTCEndpoint}. Make sure that peer metadata is serializable.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const client = new FishjamClient<PeerMetadata, TrackMetadata>();
72
+ *
73
+ * client.connect({
74
+ * peerMetadata: {},
75
+ * token: peerToken
76
+ * });
77
+ * ```
78
+ *
79
+ * @param {ConnectConfig} config - Configuration object for the client
80
+ */
81
+ connect(config) {
82
+ this.reconnectManager.reset(config.peerMetadata);
83
+ this.connectConfig = config;
84
+ this.initConnection(config.peerMetadata);
85
+ }
86
+ async initConnection(peerMetadata) {
87
+ if (this.status === 'initialized') {
88
+ this.disconnect();
89
+ }
90
+ this.webrtc = new WebRTCEndpoint({
91
+ endpointMetadataParser: this.peerMetadataParser,
92
+ trackMetadataParser: this.trackMetadataParser,
93
+ });
94
+ this.initWebsocket(peerMetadata);
95
+ this.setupCallbacks();
96
+ this.status = 'initialized';
97
+ }
98
+ initWebsocket(peerMetadata) {
99
+ if (!this.connectConfig)
100
+ throw Error('ConnectConfig is null');
101
+ const { token, signaling } = this.connectConfig;
102
+ const protocol = signaling?.protocol ?? 'ws';
103
+ const host = signaling?.host ?? 'localhost:5002';
104
+ const path = signaling?.path ?? '/socket/peer/websocket';
105
+ const websocketUrl = protocol + '://' + host + path;
106
+ this.websocket = new WebSocket(websocketUrl);
107
+ this.websocket.binaryType = 'arraybuffer';
108
+ const socketOpenHandler = (event) => {
109
+ this.emit('socketOpen', event);
110
+ const message = PeerMessage.encode({ authRequest: { token } }).finish();
111
+ this.websocket?.send(message);
112
+ };
113
+ const socketErrorHandler = (event) => {
114
+ this.emit('socketError', event);
115
+ };
116
+ const socketCloseHandler = (event) => {
117
+ if (isAuthError(event.reason)) {
118
+ this.emit('authError', event.reason);
119
+ }
120
+ this.emit('socketClose', event);
121
+ };
122
+ this.websocket.addEventListener('open', socketOpenHandler);
123
+ this.websocket.addEventListener('error', socketErrorHandler);
124
+ this.websocket.addEventListener('close', socketCloseHandler);
125
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
126
+ const messageHandler = (event) => {
127
+ const uint8Array = new Uint8Array(event.data);
128
+ try {
129
+ const data = PeerMessage.decode(uint8Array);
130
+ if (data.authenticated !== undefined) {
131
+ this.emit('authSuccess');
132
+ this.webrtc?.connect(peerMetadata);
133
+ }
134
+ else if (data.authRequest !== undefined) {
135
+ console.warn('Received unexpected control message: authRequest');
136
+ }
137
+ else if (data.mediaEvent !== undefined) {
138
+ this.webrtc?.receiveMediaEvent(data.mediaEvent.data);
139
+ }
140
+ }
141
+ catch (e) {
142
+ console.warn(`Received invalid control message, error: ${e}`);
143
+ }
144
+ };
145
+ this.websocket.addEventListener('message', messageHandler);
146
+ this.removeEventListeners = () => {
147
+ this.websocket?.removeEventListener('open', socketOpenHandler);
148
+ this.websocket?.removeEventListener('error', socketErrorHandler);
149
+ this.websocket?.removeEventListener('close', socketCloseHandler);
150
+ this.websocket?.removeEventListener('message', messageHandler);
151
+ };
152
+ }
153
+ /**
154
+ * Retrieves statistics related to the RTCPeerConnection.
155
+ * These statistics provide insights into the performance and status of the connection.
156
+ *
157
+ * @return {Promise<RTCStatsReport>}
158
+ *
159
+ * @external RTCPeerConnection#getStats()
160
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/getStats | MDN Web Docs: RTCPeerConnection.getStats()}
161
+ */
162
+ async getStatistics(selector) {
163
+ return (await this.webrtc?.getStatistics(selector)) ?? new Map();
164
+ }
165
+ /**
166
+ * Returns a snapshot of currently received remote tracks.
167
+ *
168
+ * @example
169
+ * if (client.getRemoteTracks()[trackId]?.simulcastConfig?.enabled) {
170
+ * client.setTargetTrackEncoding(trackId, encoding);
171
+ * }
172
+ */
173
+ getRemoteTracks() {
174
+ return this.webrtc?.getRemoteTracks() ?? {};
175
+ }
176
+ /**
177
+ * Returns a snapshot of currently received remote peers.
178
+ */
179
+ getRemotePeers() {
180
+ return Object.entries(this.webrtc?.getRemoteEndpoints() ?? {}).reduce((acc, [id, peer]) => (isPeer(peer) ? { ...acc, [id]: peer } : acc), {});
181
+ }
182
+ getRemoteComponents() {
183
+ return Object.entries(this.webrtc?.getRemoteEndpoints() ?? {}).reduce((acc, [id, component]) => isComponent(component) ? { ...acc, [id]: component } : acc, {});
184
+ }
185
+ getLocalPeer() {
186
+ return this.webrtc?.getLocalEndpoint() || null;
187
+ }
188
+ getBandwidthEstimation() {
189
+ if (!this.webrtc)
190
+ throw Error('Webrtc not initialized');
191
+ return this.webrtc?.getBandwidthEstimation();
192
+ }
193
+ setupCallbacks() {
194
+ this.webrtc?.on('sendMediaEvent', (mediaEvent) => {
195
+ const message = PeerMessage.encode({
196
+ mediaEvent: { data: mediaEvent },
197
+ }).finish();
198
+ this.websocket?.send(message);
199
+ });
200
+ this.webrtc?.on('connected', async (peerId, endpointsInRoom) => {
201
+ const peers = endpointsInRoom
202
+ .filter((endpoint) => isPeer(endpoint))
203
+ .map((peer) => peer);
204
+ const components = endpointsInRoom
205
+ .filter((endpoint) => isComponent(endpoint))
206
+ .map((component) => component);
207
+ await this.reconnectManager.handleReconnect();
208
+ this.sendStatisticsInterval = setInterval(() => this.sendStatistics(), STATISTICS_INTERVAL);
209
+ this.emit('joined', peerId, peers, components);
210
+ });
211
+ this.webrtc?.on('disconnected', () => {
212
+ this.emit('disconnected');
213
+ clearInterval(this.sendStatisticsInterval);
214
+ });
215
+ this.webrtc?.on('endpointAdded', (endpoint) => {
216
+ if (isPeer(endpoint)) {
217
+ this.emit('peerJoined', endpoint);
218
+ }
219
+ if (isComponent(endpoint)) {
220
+ this.emit('componentAdded', endpoint);
221
+ }
222
+ });
223
+ this.webrtc?.on('endpointRemoved', (endpoint) => {
224
+ if (isPeer(endpoint)) {
225
+ this.emit('peerLeft', endpoint);
226
+ }
227
+ if (isComponent(endpoint)) {
228
+ this.emit('componentRemoved', endpoint);
229
+ }
230
+ });
231
+ this.webrtc?.on('endpointUpdated', (endpoint) => {
232
+ if (isPeer(endpoint)) {
233
+ this.emit('peerUpdated', endpoint);
234
+ }
235
+ if (isComponent(endpoint)) {
236
+ this.emit('componentUpdated', endpoint);
237
+ }
238
+ });
239
+ this.webrtc?.on('trackReady', (ctx) => {
240
+ if (!isPeer(ctx.endpoint))
241
+ return;
242
+ this.emit('trackReady', ctx);
243
+ });
244
+ this.webrtc?.on('trackAdded', (ctx) => {
245
+ if (!isPeer(ctx.endpoint))
246
+ return;
247
+ this.emit('trackAdded', ctx);
248
+ });
249
+ this.webrtc?.on('trackRemoved', (ctx) => {
250
+ if (!isPeer(ctx.endpoint))
251
+ return;
252
+ this.emit('trackRemoved', ctx);
253
+ ctx.removeAllListeners();
254
+ });
255
+ this.webrtc?.on('trackUpdated', (ctx) => {
256
+ if (!isPeer(ctx.endpoint))
257
+ return;
258
+ this.emit('trackUpdated', ctx);
259
+ });
260
+ this.webrtc?.on('tracksPriorityChanged', (enabledTracks, disabledTracks) => {
261
+ this.emit('tracksPriorityChanged', enabledTracks, disabledTracks);
262
+ });
263
+ this.webrtc?.on('signalingError', (error) => {
264
+ this.emit('joinError', error);
265
+ });
266
+ this.webrtc?.on('connectionError', (error) => {
267
+ this.emit('connectionError', error);
268
+ });
269
+ this.webrtc?.on('bandwidthEstimationChanged', (estimation) => {
270
+ this.emit('bandwidthEstimationChanged', estimation);
271
+ });
272
+ this.webrtc?.on('targetTrackEncodingRequested', (event) => {
273
+ this.emit('targetTrackEncodingRequested', event);
274
+ });
275
+ this.webrtc?.on('localTrackAdded', (event) => {
276
+ this.emit('localTrackAdded', event);
277
+ });
278
+ this.webrtc?.on('localTrackRemoved', (event) => {
279
+ this.emit('localTrackRemoved', event);
280
+ });
281
+ this.webrtc?.on('localTrackReplaced', (event) => {
282
+ this.emit('localTrackReplaced', event);
283
+ });
284
+ this.webrtc?.on('localTrackBandwidthSet', (event) => {
285
+ this.emit('localTrackBandwidthSet', event);
286
+ });
287
+ this.webrtc?.on('localTrackMuted', (event) => {
288
+ this.emit('localTrackMuted', event);
289
+ });
290
+ this.webrtc?.on('localTrackUnmuted', (event) => {
291
+ this.emit('localTrackUnmuted', event);
292
+ });
293
+ this.webrtc?.on('localTrackBandwidthSet', (event) => {
294
+ this.emit('localTrackBandwidthSet', event);
295
+ });
296
+ this.webrtc?.on('localTrackEncodingEnabled', (event) => {
297
+ this.emit('localTrackEncodingEnabled', event);
298
+ });
299
+ this.webrtc?.on('localTrackEncodingDisabled', (event) => {
300
+ this.emit('localTrackEncodingDisabled', event);
301
+ });
302
+ this.webrtc?.on('localEndpointMetadataChanged', (event) => {
303
+ this.emit('localPeerMetadataChanged', event);
304
+ });
305
+ this.webrtc?.on('localTrackMetadataChanged', (event) => {
306
+ this.emit('localTrackMetadataChanged', event);
307
+ });
308
+ this.webrtc?.on('disconnectRequested', (event) => {
309
+ this.emit('disconnectRequested', event);
310
+ });
311
+ }
312
+ async sendStatistics() {
313
+ const statistics = await this.getStatistics();
314
+ const tracksStatistics = {};
315
+ statistics.forEach((report, key) => {
316
+ if (report.type === 'inbound-rtp' || report.type === 'outbound-rtp')
317
+ tracksStatistics[key] = report;
318
+ });
319
+ const message = PeerMessage.encode({
320
+ rtcStatsReport: { data: JSON.stringify(tracksStatistics) },
321
+ }).finish();
322
+ this.websocket?.send(message);
323
+ }
324
+ /**
325
+ * Register a callback to be called when the event is emitted.
326
+ * Full list of callbacks can be found here {@link MessageEvents}.
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * const callback = ()=>{ };
331
+ *
332
+ * client.on("onJoinSuccess", callback);
333
+ * ```
334
+ *
335
+ * @param event - Event name from {@link MessageEvents}
336
+ * @param listener - Callback function to be called when the event is emitted
337
+ * @returns This
338
+ */
339
+ on(event, listener) {
340
+ return super.on(event, listener);
341
+ }
342
+ /**
343
+ * Remove a callback from the list of callbacks to be called when the event is emitted.
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * const callback = ()=>{ };
348
+ *
349
+ * client.on("onJoinSuccess", callback);
350
+ *
351
+ * client.off("onJoinSuccess", callback);
352
+ * ```
353
+ *
354
+ * @param event - Event name from {@link MessageEvents}
355
+ * @param listener - Reference to function to be removed from called callbacks
356
+ * @returns This
357
+ */
358
+ off(event, listener) {
359
+ return super.off(event, listener);
360
+ }
361
+ handleWebRTCNotInitialized() {
362
+ return new Error('WebRTC is not initialized');
363
+ }
364
+ /**
365
+ * Adds track that will be sent to the RTC Engine.
366
+ *
367
+ * @example
368
+ * ```ts
369
+ * const localStream: MediaStream = new MediaStream();
370
+ * try {
371
+ * const localAudioStream = await navigator.mediaDevices.getUserMedia(
372
+ * { audio: true }
373
+ * );
374
+ * localAudioStream
375
+ * .getTracks()
376
+ * .forEach((track) => localStream.addTrack(track));
377
+ * } catch (error) {
378
+ * console.error("Couldn't get microphone permission:", error);
379
+ * }
380
+ *
381
+ * try {
382
+ * const localVideoStream = await navigator.mediaDevices.getUserMedia(
383
+ * { video: true }
384
+ * );
385
+ * localVideoStream
386
+ * .getTracks()
387
+ * .forEach((track) => localStream.addTrack(track));
388
+ * } catch (error) {
389
+ * console.error("Couldn't get camera permission:", error);
390
+ * }
391
+ *
392
+ * localStream
393
+ * .getTracks()
394
+ * .forEach((track) => client.addTrack(track, localStream));
395
+ * ```
396
+ *
397
+ * @param track - Audio or video track e.g. from your microphone or camera.
398
+ * @param stream - Stream that this track belongs to.
399
+ * @param trackMetadata - Any information about this track that other peers will receive in
400
+ * {@link MessageEvents.peerJoined}. E.g. this can source of the track - wheather it's screensharing, webcam or some
401
+ * other media device.
402
+ * @param simulcastConfig - Simulcast configuration. By default, simulcast is disabled. For more information refer to
403
+ * {@link !SimulcastConfig | SimulcastConfig}.
404
+ * @param maxBandwidth - Maximal bandwidth this track can use. Defaults to 0 which is unlimited. This option has no
405
+ * effect for simulcast and audio tracks. For simulcast tracks use {@link FishjamClient.setTrackBandwidth}.
406
+ * @returns {string} Returns id of added track
407
+ */
408
+ addTrack(track, trackMetadata, simulcastConfig = {
409
+ enabled: false,
410
+ activeEncodings: [],
411
+ disabledEncodings: [],
412
+ }, maxBandwidth = 0) {
413
+ if (!this.webrtc)
414
+ throw this.handleWebRTCNotInitialized();
415
+ return this.webrtc.addTrack(track, trackMetadata, simulcastConfig, maxBandwidth);
416
+ }
417
+ /**
418
+ * Replaces a track that is being sent to the RTC Engine.
419
+ *
420
+ * @example
421
+ * ```ts
422
+ * // setup camera
423
+ * let localStream: MediaStream = new MediaStream();
424
+ * try {
425
+ * localVideoStream = await navigator.mediaDevices.getUserMedia(
426
+ * VIDEO_CONSTRAINTS
427
+ * );
428
+ * localVideoStream
429
+ * .getTracks()
430
+ * .forEach((track) => localStream.addTrack(track));
431
+ * } catch (error) {
432
+ * console.error("Couldn't get camera permission:", error);
433
+ * }
434
+ * let oldTrackId;
435
+ * localStream
436
+ * .getTracks()
437
+ * .forEach((track) => trackId = webrtc.addTrack(track, localStream));
438
+ *
439
+ * // change camera
440
+ * const oldTrack = localStream.getVideoTracks()[0];
441
+ * let videoDeviceId = "abcd-1234";
442
+ * navigator.mediaDevices.getUserMedia({
443
+ * video: {
444
+ * ...(VIDEO_CONSTRAINTS as {}),
445
+ * deviceId: {
446
+ * exact: videoDeviceId,
447
+ * },
448
+ * }
449
+ * })
450
+ * .then((stream) => {
451
+ * let videoTrack = stream.getVideoTracks()[0];
452
+ * webrtc.replaceTrack(oldTrackId, videoTrack);
453
+ * })
454
+ * .catch((error) => {
455
+ * console.error('Error switching camera', error);
456
+ * })
457
+ * ```
458
+ *
459
+ * @param {string} trackId - Id of audio or video track to replace.
460
+ * @param {MediaStreamTrack} newTrack - New audio or video track.
461
+ * @param {TrackMetadata} [newTrackMetadata] - Optional track metadata to apply to the new track. If no track metadata is passed, the
462
+ * old track metadata is retained.
463
+ * @returns {Promise<boolean>} Success
464
+ */
465
+ async replaceTrack(trackId, newTrack, newTrackMetadata) {
466
+ if (!this.webrtc)
467
+ throw this.handleWebRTCNotInitialized();
468
+ return this.webrtc.replaceTrack(trackId, newTrack, newTrackMetadata);
469
+ }
470
+ /**
471
+ * Updates maximum bandwidth for the track identified by trackId. This value directly translates to quality of the
472
+ * stream and, in case of video, to the amount of RTP packets being sent. In case trackId points at the simulcast
473
+ * track bandwidth is split between all of the variant streams proportionally to their resolution.
474
+ *
475
+ * @param {string} trackId
476
+ * @param {BandwidthLimit} bandwidth In kbps
477
+ * @returns {Promise<boolean>} Success
478
+ */
479
+ async setTrackBandwidth(trackId, bandwidth) {
480
+ if (!this.webrtc)
481
+ throw this.handleWebRTCNotInitialized();
482
+ await this.webrtc.setTrackBandwidth(trackId, bandwidth);
483
+ return true;
484
+ }
485
+ /**
486
+ * Updates maximum bandwidth for the given simulcast encoding of the given track.
487
+ *
488
+ * @param {string} trackId - Id of the track
489
+ * @param {string} rid - Rid of the encoding
490
+ * @param {BandwidthLimit} bandwidth - Desired max bandwidth used by the encoding (in kbps)
491
+ * @returns
492
+ */
493
+ async setEncodingBandwidth(trackId, rid, bandwidth) {
494
+ if (!this.webrtc)
495
+ throw this.handleWebRTCNotInitialized();
496
+ await this.webrtc.setEncodingBandwidth(trackId, rid, bandwidth);
497
+ return true;
498
+ }
499
+ /**
500
+ * Removes a track from connection that was being sent to the RTC Engine.
501
+ *
502
+ * @example
503
+ * ```ts
504
+ * // setup camera
505
+ * let localStream: MediaStream = new MediaStream();
506
+ * try {
507
+ * localVideoStream = await navigator.mediaDevices.getUserMedia(
508
+ * VIDEO_CONSTRAINTS
509
+ * );
510
+ * localVideoStream
511
+ * .getTracks()
512
+ * .forEach((track) => localStream.addTrack(track));
513
+ * } catch (error) {
514
+ * console.error("Couldn't get camera permission:", error);
515
+ * }
516
+ *
517
+ * let trackId
518
+ * localStream
519
+ * .getTracks()
520
+ * .forEach((track) => trackId = webrtc.addTrack(track, localStream));
521
+ *
522
+ * // remove track
523
+ * webrtc.removeTrack(trackId)
524
+ * ```
525
+ *
526
+ * @param {string} trackId - Id of audio or video track to remove.
527
+ */
528
+ removeTrack(trackId) {
529
+ if (!this.webrtc)
530
+ throw this.handleWebRTCNotInitialized();
531
+ return this.webrtc.removeTrack(trackId);
532
+ }
533
+ /**
534
+ * Sets track encoding that server should send to the client library.
535
+ *
536
+ * The encoding will be sent whenever it is available. If chosen encoding is temporarily unavailable, some other
537
+ * encoding will be sent until chosen encoding becomes active again.
538
+ *
539
+ * @example
540
+ * ```ts
541
+ * webrtc.setTargetTrackEncoding(incomingTrackCtx.trackId, "l")
542
+ * ```
543
+ *
544
+ * @param {string} trackId - Id of track
545
+ * @param {Encoding} encoding - Encoding to receive
546
+ */
547
+ setTargetTrackEncoding(trackId, encoding) {
548
+ if (!this.webrtc)
549
+ throw this.handleWebRTCNotInitialized();
550
+ return this.webrtc.setTargetTrackEncoding(trackId, encoding);
551
+ }
552
+ /**
553
+ * Enables track encoding so that it will be sent to the server.
554
+ *
555
+ * @example
556
+ * ```ts
557
+ * const trackId = webrtc.addTrack(track, stream, {}, {enabled: true, active_encodings: ["l", "m", "h"]});
558
+ * webrtc.disableTrackEncoding(trackId, "l");
559
+ * // wait some time
560
+ * webrtc.enableTrackEncoding(trackId, "l");
561
+ * ```
562
+ *
563
+ * @param {string} trackId - Id of track
564
+ * @param {Encoding} encoding - Encoding that will be enabled
565
+ */
566
+ enableTrackEncoding(trackId, encoding) {
567
+ if (!this.webrtc)
568
+ throw this.handleWebRTCNotInitialized();
569
+ return this.webrtc.enableTrackEncoding(trackId, encoding);
570
+ }
571
+ /**
572
+ * Disables track encoding so that it will be no longer sent to the server.
573
+ *
574
+ * @example
575
+ * ```ts
576
+ * const trackId = webrtc.addTrack(track, stream, {}, {enabled: true, active_encodings: ["l", "m", "h"]});
577
+ * webrtc.disableTrackEncoding(trackId, "l");
578
+ * ```
579
+ *
580
+ * @param {string} trackId - Id of track
581
+ * @param {rackEncoding} encoding - Encoding that will be disabled
582
+ */
583
+ disableTrackEncoding(trackId, encoding) {
584
+ if (!this.webrtc)
585
+ throw this.handleWebRTCNotInitialized();
586
+ return this.webrtc.disableTrackEncoding(trackId, encoding);
587
+ }
588
+ /**
589
+ * Updates the metadata for the current peer.
590
+ *
591
+ * @param peerMetadata - Data about this peer that other peers will receive upon joining.
592
+ *
593
+ * If the metadata is different from what is already tracked in the room, the event {@link MessageEvents.peerUpdated} will
594
+ * be emitted for other peers in the room.
595
+ */
596
+ updatePeerMetadata = (peerMetadata) => {
597
+ if (!this.webrtc)
598
+ throw this.handleWebRTCNotInitialized();
599
+ this.webrtc.updateEndpointMetadata(peerMetadata);
600
+ };
601
+ /**
602
+ * Updates the metadata for a specific track.
603
+ *
604
+ * @param trackId - TrackId (generated in addTrack) of audio or video track.
605
+ * @param trackMetadata - Data about this track that other peers will receive upon joining.
606
+ *
607
+ * If the metadata is different from what is already tracked in the room, the event {@link MessageEvents.trackUpdated} will
608
+ * be emitted for other peers in the room.
609
+ */
610
+ updateTrackMetadata = (trackId, trackMetadata) => {
611
+ if (!this.webrtc)
612
+ throw this.handleWebRTCNotInitialized();
613
+ this.webrtc.updateTrackMetadata(trackId, trackMetadata);
614
+ };
615
+ isReconnecting() {
616
+ return this.reconnectManager.isReconnecting();
617
+ }
618
+ /**
619
+ * Leaves the room. This function should be called when user leaves the room in a clean way e.g. by clicking a
620
+ * dedicated, custom button `disconnect`. As a result there will be generated one more media event that should be sent
621
+ * to the RTC Engine. Thanks to it each other peer will be notified that peer left in {@link MessageEvents.peerLeft},
622
+ */
623
+ leave = () => {
624
+ if (!this.webrtc)
625
+ throw this.handleWebRTCNotInitialized();
626
+ this.webrtc.disconnect();
627
+ };
628
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
629
+ isOpen(websocket) {
630
+ return websocket?.readyState === 1;
631
+ }
632
+ /**
633
+ * Disconnect from the room, and close the websocket connection. Tries to leave the room gracefully, but if it fails,
634
+ * it will close the websocket anyway.
635
+ *
636
+ * @example
637
+ * ```typescript
638
+ * const client = new FishjamClient<PeerMetadata, TrackMetadata>();
639
+ *
640
+ * client.connect({ ... });
641
+ *
642
+ * client.disconnect();
643
+ * ```
644
+ */
645
+ disconnect() {
646
+ try {
647
+ this.webrtc?.removeAllListeners();
648
+ this.webrtc?.disconnect();
649
+ this.webrtc?.cleanUp();
650
+ }
651
+ catch (e) {
652
+ console.warn(e);
653
+ }
654
+ this.removeEventListeners?.();
655
+ this.removeEventListeners = null;
656
+ if (this.isOpen(this.websocket || null)) {
657
+ this.websocket?.close();
658
+ }
659
+ this.websocket = null;
660
+ this.webrtc = null;
661
+ this.emit('disconnected');
662
+ }
663
+ cleanup() {
664
+ this.reconnectManager.cleanup();
665
+ }
666
+ }
@@ -0,0 +1,3 @@
1
+ export declare const AUTH_ERROR_REASONS: readonly ["missing token", "invalid token", "expired token", "room not found", "peer not found"];
2
+ export type AuthErrorReason = (typeof AUTH_ERROR_REASONS)[number];
3
+ export declare const isAuthError: (error: string) => error is AuthErrorReason;
@@ -0,0 +1,8 @@
1
+ export const AUTH_ERROR_REASONS = [
2
+ 'missing token',
3
+ 'invalid token',
4
+ 'expired token',
5
+ 'room not found',
6
+ 'peer not found',
7
+ ];
8
+ export const isAuthError = (error) => AUTH_ERROR_REASONS.includes(error);
@@ -0,0 +1,7 @@
1
+ export type { Peer, Component, ConnectConfig, CreateConfig, MessageEvents, SignalingUrl, } from './FishjamClient';
2
+ export type { ReconnectConfig, ReconnectionStatus } from './reconnection';
3
+ export type { AuthErrorReason } from './auth.js';
4
+ export { isAuthError, AUTH_ERROR_REASONS } from './auth.js';
5
+ export { FishjamClient } from './FishjamClient';
6
+ export type { TrackBandwidthLimit, SimulcastBandwidthLimit, BandwidthLimit, WebRTCEndpointEvents, TrackContextEvents, Endpoint, SimulcastConfig, TrackContext, Encoding, VadStatus, EncodingReason, MetadataParser, } from './webrtc';
7
+ export * from './webrtc';
@@ -0,0 +1,3 @@
1
+ export { isAuthError, AUTH_ERROR_REASONS } from './auth.js';
2
+ export { FishjamClient } from './FishjamClient';
3
+ export * from './webrtc';