@livekit/rtc-node 0.13.20 → 0.13.22

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 (75) hide show
  1. package/Cargo.toml +6 -3
  2. package/dist/async_queue.cjs +80 -0
  3. package/dist/async_queue.cjs.map +1 -0
  4. package/dist/async_queue.d.cts +30 -0
  5. package/dist/async_queue.d.ts +30 -0
  6. package/dist/async_queue.d.ts.map +1 -0
  7. package/dist/async_queue.js +56 -0
  8. package/dist/async_queue.js.map +1 -0
  9. package/dist/audio_mixer.cjs +281 -0
  10. package/dist/audio_mixer.cjs.map +1 -0
  11. package/dist/audio_mixer.d.cts +121 -0
  12. package/dist/audio_mixer.d.ts +121 -0
  13. package/dist/audio_mixer.d.ts.map +1 -0
  14. package/dist/audio_mixer.js +256 -0
  15. package/dist/audio_mixer.js.map +1 -0
  16. package/dist/index.cjs +3 -0
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +3 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/participant.cjs +43 -32
  24. package/dist/participant.cjs.map +1 -1
  25. package/dist/participant.d.cts +3 -0
  26. package/dist/participant.d.ts +3 -0
  27. package/dist/participant.d.ts.map +1 -1
  28. package/dist/participant.js +43 -32
  29. package/dist/participant.js.map +1 -1
  30. package/dist/proto/data_stream_pb.cjs +91 -2
  31. package/dist/proto/data_stream_pb.cjs.map +1 -1
  32. package/dist/proto/data_stream_pb.d.cts +92 -1
  33. package/dist/proto/data_stream_pb.d.ts +92 -1
  34. package/dist/proto/data_stream_pb.d.ts.map +1 -1
  35. package/dist/proto/data_stream_pb.js +88 -2
  36. package/dist/proto/data_stream_pb.js.map +1 -1
  37. package/dist/proto/ffi_pb.cjs +6 -3
  38. package/dist/proto/ffi_pb.cjs.map +1 -1
  39. package/dist/proto/ffi_pb.d.cts +19 -1
  40. package/dist/proto/ffi_pb.d.ts +19 -1
  41. package/dist/proto/ffi_pb.d.ts.map +1 -1
  42. package/dist/proto/ffi_pb.js +7 -4
  43. package/dist/proto/ffi_pb.js.map +1 -1
  44. package/dist/proto/room_pb.cjs +32 -2
  45. package/dist/proto/room_pb.cjs.map +1 -1
  46. package/dist/proto/room_pb.d.cts +38 -2
  47. package/dist/proto/room_pb.d.ts +38 -2
  48. package/dist/proto/room_pb.d.ts.map +1 -1
  49. package/dist/proto/room_pb.js +31 -2
  50. package/dist/proto/room_pb.js.map +1 -1
  51. package/dist/room.cjs +173 -80
  52. package/dist/room.cjs.map +1 -1
  53. package/dist/room.d.cts +16 -3
  54. package/dist/room.d.ts +16 -3
  55. package/dist/room.d.ts.map +1 -1
  56. package/dist/room.js +174 -81
  57. package/dist/room.js.map +1 -1
  58. package/dist/version.cjs +1 -1
  59. package/dist/version.cjs.map +1 -1
  60. package/dist/version.d.cts +1 -1
  61. package/dist/version.d.ts +1 -1
  62. package/dist/version.js +1 -1
  63. package/dist/version.js.map +1 -1
  64. package/package.json +9 -8
  65. package/src/async_queue.test.ts +250 -0
  66. package/src/async_queue.ts +80 -0
  67. package/src/audio_mixer.test.ts +167 -0
  68. package/src/audio_mixer.ts +407 -0
  69. package/src/index.ts +1 -0
  70. package/src/participant.ts +48 -30
  71. package/src/proto/data_stream_pb.ts +159 -0
  72. package/src/proto/ffi_pb.ts +22 -1
  73. package/src/proto/room_pb.ts +64 -1
  74. package/src/room.ts +193 -91
  75. package/src/version.ts +1 -1
package/src/room.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
+ import { Mutex } from '@livekit/mutex';
4
5
  import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
5
6
  import EventEmitter from 'events';
6
7
  import { ByteStreamReader, TextStreamReader } from './data_streams/stream_reader.js';
@@ -17,10 +18,10 @@ import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
17
18
  import { log } from './log.js';
18
19
  import type { Participant } from './participant.js';
19
20
  import { LocalParticipant, RemoteParticipant } from './participant.js';
20
- import { EncryptionState } from './proto/e2ee_pb.js';
21
+ import { EncryptionState, EncryptionType } from './proto/e2ee_pb.js';
21
22
  import type { FfiEvent } from './proto/ffi_pb.js';
22
23
  import type { DisconnectReason, OwnedParticipant } from './proto/participant_pb.js';
23
- import type { DataStream_Trailer } from './proto/room_pb.js';
24
+ import type { DataStream_Trailer, DisconnectCallback } from './proto/room_pb.js';
24
25
  import {
25
26
  type ConnectCallback,
26
27
  ConnectRequest,
@@ -60,7 +61,11 @@ export const defaultRtcConfiguration: RtcConfiguration = {
60
61
  export interface RoomOptions {
61
62
  autoSubscribe: boolean;
62
63
  dynacast: boolean;
64
+ /**
65
+ * @deprecated Use `encryption` instead. See x for details
66
+ */
63
67
  e2ee?: E2EEOptions;
68
+ encryption?: E2EEOptions;
64
69
  rtcConfig?: RtcConfiguration;
65
70
  }
66
71
 
@@ -68,6 +73,7 @@ export const defaultRoomOptions = new FfiRoomOptions({
68
73
  autoSubscribe: true,
69
74
  dynacast: false,
70
75
  e2ee: undefined,
76
+ encryption: undefined,
71
77
  rtcConfig: undefined,
72
78
  adaptiveStream: false,
73
79
  joinRetries: 1,
@@ -76,6 +82,12 @@ export const defaultRoomOptions = new FfiRoomOptions({
76
82
  export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>) {
77
83
  private info?: RoomInfo;
78
84
  private ffiHandle?: FfiHandle;
85
+ /**
86
+ * used to ensure events are processed sequentially and allow for
87
+ * the local participant to acquire the lock while doing state updates related to FFI events
88
+ * before processing the next events
89
+ */
90
+ private ffiEventLock = new Mutex();
79
91
 
80
92
  private byteStreamControllers = new Map<string, StreamController<DataStream_Chunk>>();
81
93
  private textStreamControllers = new Map<string, StreamController<DataStream_Chunk>>();
@@ -174,7 +186,10 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
174
186
  */
175
187
  async connect(url: string, token: string, opts?: RoomOptions) {
176
188
  const options = { ...defaultRoomOptions, ...opts };
177
- const e2eeOptions = { ...defaultE2EEOptions, ...options.e2ee };
189
+ const e2eeEnabled = options.encryption || options.e2ee;
190
+ const e2eeOptions = options.encryption
191
+ ? { ...defaultE2EEOptions, ...options.encryption }
192
+ : { ...defaultE2EEOptions, ...options.e2ee };
178
193
 
179
194
  const req = new ConnectRequest({
180
195
  url: url,
@@ -200,11 +215,14 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
200
215
  switch (cb.message.case) {
201
216
  case 'result':
202
217
  this.ffiHandle = new FfiHandle(cb.message.value.room!.handle!.id!);
203
- this.e2eeManager = options.e2ee && new E2EEManager(this.ffiHandle.handle, e2eeOptions);
218
+ this.e2eeManager = e2eeEnabled && new E2EEManager(this.ffiHandle.handle, e2eeOptions);
204
219
 
205
220
  this.info = cb.message.value.room!.info;
206
221
  this.connectionState = ConnectionState.CONN_CONNECTED;
207
- this.localParticipant = new LocalParticipant(cb.message.value.localParticipant!);
222
+ this.localParticipant = new LocalParticipant(
223
+ cb.message.value.localParticipant!,
224
+ this.ffiEventLock,
225
+ );
208
226
 
209
227
  for (const pt of cb.message.value.participants) {
210
228
  const rp = this.createRemoteParticipant(pt.participant!);
@@ -230,7 +248,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
230
248
  return;
231
249
  }
232
250
 
233
- FfiClient.instance.request<DisconnectResponse>({
251
+ const res = FfiClient.instance.request<DisconnectResponse>({
234
252
  message: {
235
253
  case: 'disconnect',
236
254
  value: {
@@ -239,6 +257,10 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
239
257
  },
240
258
  });
241
259
 
260
+ await FfiClient.instance.waitFor<DisconnectCallback>((ev: FfiEvent) => {
261
+ return ev.message.case == 'disconnect' && ev.message.value.asyncId == res.asyncId;
262
+ });
263
+
242
264
  FfiClient.instance.removeListener(FfiClientEvent.FfiEvent, this.onFfiEvent);
243
265
  this.removeAllListeners();
244
266
  }
@@ -279,22 +301,27 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
279
301
  this.byteStreamHandlers.delete(topic);
280
302
  }
281
303
 
282
- private onFfiEvent = (ffiEvent: FfiEvent) => {
283
- if (!this.localParticipant || !this.ffiHandle || !this.info) {
284
- this.preConnectEvents.push(ffiEvent);
285
- return;
286
- }
304
+ private onFfiEvent = async (ffiEvent: FfiEvent) => {
305
+ const unlock = await this.ffiEventLock.lock();
306
+ try {
307
+ if (!this.localParticipant || !this.ffiHandle || !this.info) {
308
+ this.preConnectEvents.push(ffiEvent);
309
+ return;
310
+ }
287
311
 
288
- // process preConnectEvents if we received the connectCallback after the events were queued
289
- for (const ev of this.preConnectEvents) {
290
- this.processFfiEvent(ev);
291
- }
292
- this.preConnectEvents = [];
312
+ // process preConnectEvents if we received the connectCallback after the events were queued
313
+ for (const ev of this.preConnectEvents) {
314
+ await this.processFfiEvent(ev);
315
+ }
316
+ this.preConnectEvents = [];
293
317
 
294
- this.processFfiEvent(ffiEvent);
318
+ await this.processFfiEvent(ffiEvent);
319
+ } finally {
320
+ unlock();
321
+ }
295
322
  };
296
323
 
297
- private processFfiEvent = (ffiEvent: FfiEvent) => {
324
+ private processFfiEvent = async (ffiEvent: FfiEvent) => {
298
325
  if (!this.localParticipant || !this.ffiHandle || !this.info) {
299
326
  throw new Error('processFfiEvent called before connect');
300
327
  }
@@ -330,24 +357,38 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
330
357
  this.emit(RoomEvent.ParticipantConnected, participant);
331
358
  } else if (ev.case == 'participantDisconnected') {
332
359
  const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
333
- this.remoteParticipants.delete(participant!.identity);
334
- participant!.info.disconnectReason = ev.value.disconnectReason;
335
- this.emit(RoomEvent.ParticipantDisconnected, participant!);
360
+ if (participant) {
361
+ this.remoteParticipants.delete(participant.identity);
362
+ participant.info.disconnectReason = ev.value.disconnectReason;
363
+ this.emit(RoomEvent.ParticipantDisconnected, participant);
364
+ } else {
365
+ console.log(`RoomEvent.ParticipantDisconnected: Could not find participant`);
366
+ }
336
367
  } else if (ev.case == 'localTrackPublished') {
337
- const publication = this.localParticipant!.trackPublications.get(ev.value.trackSid!);
338
- this.emit(RoomEvent.LocalTrackPublished, publication!, this.localParticipant!);
368
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid!);
369
+ this.emit(RoomEvent.LocalTrackPublished, publication!, this.localParticipant);
339
370
  } else if (ev.case == 'localTrackUnpublished') {
340
- const publication = this.localParticipant!.trackPublications.get(ev.value.publicationSid!);
341
- this.localParticipant!.trackPublications.delete(ev.value.publicationSid!);
371
+ const publication = this.localParticipant.trackPublications.get(ev.value.publicationSid!);
372
+ this.localParticipant.trackPublications.delete(ev.value.publicationSid!);
342
373
  this.emit(RoomEvent.LocalTrackUnpublished, publication!, this.localParticipant!);
343
374
  } else if (ev.case == 'localTrackSubscribed') {
344
- const publication = this.localParticipant!.trackPublications.get(ev.value.trackSid!);
345
- publication!.resolveFirstSubscription();
346
- this.emit(RoomEvent.LocalTrackSubscribed, publication!.track!);
375
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid!);
376
+ if (publication) {
377
+ publication.resolveFirstSubscription();
378
+ this.emit(RoomEvent.LocalTrackSubscribed, publication!.track!);
379
+ } else {
380
+ console.warn(`RoomEvent.LocalTrackSubscribed: Publication not found: ${ev.value.trackSid}`);
381
+ }
347
382
  } else if (ev.case == 'trackPublished') {
348
383
  const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
349
384
  const publication = new RemoteTrackPublication(ev.value.publication!);
350
- participant!.trackPublications.set(publication.sid!, publication);
385
+ if (participant) {
386
+ participant.trackPublications.set(publication.sid!, publication);
387
+ } else {
388
+ console.warn(
389
+ `RoomEvent.TrackPublished: Could not find participant: ${ev.value.participantIdentity}`,
390
+ );
391
+ }
351
392
  this.emit(RoomEvent.TrackPublished, publication, participant!);
352
393
  } else if (ev.case == 'trackUnpublished') {
353
394
  const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
@@ -355,92 +396,139 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
355
396
  participant.trackPublications.delete(ev.value.publicationSid!);
356
397
  if (publication) {
357
398
  this.emit(RoomEvent.TrackUnpublished, publication, participant);
399
+ } else {
400
+ console.warn(`RoomEvent.TrackUnpublished: Could not find publication`);
358
401
  }
359
402
  } else if (ev.case == 'trackSubscribed') {
360
403
  const ownedTrack = ev.value.track!;
361
404
  const trackInfo = ownedTrack.info!;
362
- const { participant, publication } = this.requirePublicationOfRemoteParticipant(
363
- ev.value.participantIdentity!,
364
- trackInfo.sid!,
365
- );
366
- publication.subscribed = true;
367
- if (trackInfo.kind == TrackKind.KIND_VIDEO) {
368
- publication.track = new RemoteVideoTrack(ownedTrack);
369
- } else if (trackInfo.kind == TrackKind.KIND_AUDIO) {
370
- publication.track = new RemoteAudioTrack(ownedTrack);
371
- }
405
+ try {
406
+ const { participant, publication } = this.requirePublicationOfRemoteParticipant(
407
+ ev.value.participantIdentity!,
408
+ trackInfo.sid!,
409
+ );
410
+ publication.subscribed = true;
411
+ if (trackInfo.kind == TrackKind.KIND_VIDEO) {
412
+ publication.track = new RemoteVideoTrack(ownedTrack);
413
+ } else if (trackInfo.kind == TrackKind.KIND_AUDIO) {
414
+ publication.track = new RemoteAudioTrack(ownedTrack);
415
+ }
372
416
 
373
- this.emit(RoomEvent.TrackSubscribed, publication.track!, publication, participant);
417
+ this.emit(RoomEvent.TrackSubscribed, publication.track!, publication, participant);
418
+ } catch (e: any) {
419
+ console.warn(`RoomEvent.TrackSubscribed: ${e.message}`);
420
+ }
374
421
  } else if (ev.case == 'trackUnsubscribed') {
375
- const { participant, publication } = this.requirePublicationOfRemoteParticipant(
376
- ev.value.participantIdentity!,
377
- ev.value.trackSid!,
378
- );
379
- const track = publication.track!;
380
- publication.track = undefined;
381
- publication.subscribed = false;
382
- this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
422
+ try {
423
+ const { participant, publication } = this.requirePublicationOfRemoteParticipant(
424
+ ev.value.participantIdentity!,
425
+ ev.value.trackSid!,
426
+ );
427
+ const track = publication.track!;
428
+ publication.track = undefined;
429
+ publication.subscribed = false;
430
+ this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
431
+ } catch (e: any) {
432
+ console.warn(`RoomEvent.TrackUnsubscribed: ${e.message}`);
433
+ }
383
434
  } else if (ev.case == 'trackSubscriptionFailed') {
384
- const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
385
- this.emit(RoomEvent.TrackSubscriptionFailed, ev.value.trackSid!, participant, ev.value.error);
435
+ try {
436
+ const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
437
+ this.emit(
438
+ RoomEvent.TrackSubscriptionFailed,
439
+ ev.value.trackSid!,
440
+ participant,
441
+ ev.value.error,
442
+ );
443
+ } catch (e: any) {
444
+ console.warn(`RoomEvent.TrackSubscriptionFailed: ${e.message}`);
445
+ }
386
446
  } else if (ev.case == 'trackMuted') {
387
- const { participant, publication } = this.requirePublicationOfParticipant(
388
- ev.value.participantIdentity!,
389
- ev.value.trackSid!,
390
- );
391
- publication.info!.muted = true;
392
- if (publication.track) {
393
- publication.track.info!.muted = true;
447
+ try {
448
+ const { participant, publication } = this.requirePublicationOfParticipant(
449
+ ev.value.participantIdentity!,
450
+ ev.value.trackSid!,
451
+ );
452
+ publication.info!.muted = true;
453
+ if (publication.track) {
454
+ publication.track.info!.muted = true;
455
+ }
456
+ this.emit(RoomEvent.TrackMuted, publication, participant);
457
+ } catch (e: any) {
458
+ console.warn(`RoomEvent.TrackMuted: ${e.message}`);
394
459
  }
395
- this.emit(RoomEvent.TrackMuted, publication, participant);
396
460
  } else if (ev.case == 'trackUnmuted') {
397
- const { participant, publication } = this.requirePublicationOfParticipant(
398
- ev.value.participantIdentity!,
399
- ev.value.trackSid!,
400
- );
401
- publication.info!.muted = false;
402
- if (publication.track) {
403
- publication.track.info!.muted = false;
461
+ try {
462
+ const { participant, publication } = this.requirePublicationOfParticipant(
463
+ ev.value.participantIdentity!,
464
+ ev.value.trackSid!,
465
+ );
466
+ publication.info!.muted = false;
467
+ if (publication.track) {
468
+ publication.track.info!.muted = false;
469
+ }
470
+ this.emit(RoomEvent.TrackUnmuted, publication, participant);
471
+ } catch (e: any) {
472
+ console.warn(`RoomEvent.TrackUnmuted: ${e.message}`);
404
473
  }
405
- this.emit(RoomEvent.TrackUnmuted, publication, participant);
406
474
  } else if (ev.case == 'activeSpeakersChanged') {
407
- const activeSpeakers = ev.value.participantIdentities.map((identity) =>
408
- this.requireParticipantByIdentity(identity),
409
- );
410
- this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
475
+ try {
476
+ const activeSpeakers = ev.value.participantIdentities.map((identity) =>
477
+ this.requireParticipantByIdentity(identity),
478
+ );
479
+ this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
480
+ } catch (e: any) {
481
+ console.warn(`RoomEvent.ActiveSpeakersChanged: ${e.message}`);
482
+ }
411
483
  } else if (ev.case == 'roomMetadataChanged') {
412
- this.info!.metadata = ev.value.metadata;
413
- this.emit(RoomEvent.RoomMetadataChanged, this.info!.metadata!);
484
+ this.info.metadata = ev.value.metadata ?? '';
485
+ this.emit(RoomEvent.RoomMetadataChanged, this.info.metadata);
414
486
  } else if (ev.case == 'participantMetadataChanged') {
415
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
416
- participant.info.metadata = ev.value.metadata;
417
- this.emit(RoomEvent.ParticipantMetadataChanged, participant.metadata, participant);
487
+ try {
488
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
489
+ participant.info.metadata = ev.value.metadata;
490
+ this.emit(RoomEvent.ParticipantMetadataChanged, participant.metadata, participant);
491
+ } catch (e: any) {
492
+ console.warn(`RoomEvent.ParticipantMetadataChanged: ${e.message}`);
493
+ }
418
494
  } else if (ev.case == 'participantNameChanged') {
419
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
420
- participant.info.name = ev.value.name;
421
- this.emit(RoomEvent.ParticipantNameChanged, participant.name!, participant);
495
+ try {
496
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
497
+ participant.info.name = ev.value.name;
498
+ this.emit(RoomEvent.ParticipantNameChanged, participant.name!, participant);
499
+ } catch (e: any) {
500
+ console.warn(`RoomEvent.ParticipantNameChanged: ${e.message}`);
501
+ }
422
502
  } else if (ev.case == 'participantAttributesChanged') {
423
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
424
- participant.info.attributes = ev.value.attributes.reduce(
425
- (acc, value) => {
426
- acc[value.key!] = value.value!;
427
- return acc;
428
- },
429
- {} as Record<string, string>,
430
- );
431
- if (Object.keys(ev.value.changedAttributes).length > 0) {
432
- const changedAttributes = ev.value.changedAttributes.reduce(
503
+ try {
504
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
505
+ participant.info.attributes = ev.value.attributes.reduce(
433
506
  (acc, value) => {
434
507
  acc[value.key!] = value.value!;
435
508
  return acc;
436
509
  },
437
510
  {} as Record<string, string>,
438
511
  );
439
- this.emit(RoomEvent.ParticipantAttributesChanged, changedAttributes, participant);
512
+ if (Object.keys(ev.value.changedAttributes).length > 0) {
513
+ const changedAttributes = ev.value.changedAttributes.reduce(
514
+ (acc, value) => {
515
+ acc[value.key!] = value.value!;
516
+ return acc;
517
+ },
518
+ {} as Record<string, string>,
519
+ );
520
+ this.emit(RoomEvent.ParticipantAttributesChanged, changedAttributes, participant);
521
+ }
522
+ } catch (e: any) {
523
+ console.warn(`RoomEvent.ParticipantAttributesChanged: ${e.message}`);
440
524
  }
441
525
  } else if (ev.case == 'connectionQualityChanged') {
442
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
443
- this.emit(RoomEvent.ConnectionQualityChanged, ev.value.quality!, participant);
526
+ try {
527
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
528
+ this.emit(RoomEvent.ConnectionQualityChanged, ev.value.quality!, participant);
529
+ } catch (e: any) {
530
+ console.warn(`RoomEvent.ConnectionQualityChanged: ${e.message}`);
531
+ }
444
532
  } else if (ev.case == 'chatMessage') {
445
533
  const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity!);
446
534
  const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message!;
@@ -515,6 +603,17 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
515
603
  participant.info = info;
516
604
  }
517
605
  }
606
+ } else if (ev.case === 'participantEncryptionStatusChanged') {
607
+ try {
608
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
609
+ this.emit(
610
+ RoomEvent.ParticipantEncryptionStatusChanged,
611
+ !!ev.value.isEncrypted,
612
+ participant,
613
+ );
614
+ } catch (e: any) {
615
+ console.warn(`RoomEvent.ParticipantEncryptionStatusChanged: ${e.message}`);
616
+ }
518
617
  }
519
618
  };
520
619
 
@@ -716,12 +815,14 @@ export type RoomCallbacks = {
716
815
  changedAttributes: Record<string, string>,
717
816
  participant: Participant,
718
817
  ) => void;
818
+ participantEncryptionStatusChanged: (isEncrypted: boolean, participant: Participant) => void;
719
819
  connectionQualityChanged: (quality: ConnectionQuality, participant: Participant) => void;
720
820
  dataReceived: (
721
821
  payload: Uint8Array,
722
822
  participant?: RemoteParticipant,
723
823
  kind?: DataPacketKind,
724
824
  topic?: string,
825
+ encryptionType?: EncryptionType,
725
826
  ) => void;
726
827
  chatMessage: (message: ChatMessage, participant?: Participant) => void;
727
828
  dtmfReceived: (code: number, digit: string, participant: RemoteParticipant) => void;
@@ -755,6 +856,7 @@ export enum RoomEvent {
755
856
  ParticipantMetadataChanged = 'participantMetadataChanged',
756
857
  ParticipantNameChanged = 'participantNameChanged',
757
858
  ParticipantAttributesChanged = 'participantAttributesChanged',
859
+ ParticipantEncryptionStatusChanged = 'participantEncryptionStatusChanged',
758
860
  ConnectionQualityChanged = 'connectionQualityChanged',
759
861
  DataReceived = 'dataReceived',
760
862
  ChatMessage = 'chatMessage',
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const SDK_VERSION = "0.13.20";
1
+ export const SDK_VERSION = "0.13.22";