@livekit/rtc-node 0.13.21 → 0.13.23

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 (135) hide show
  1. package/dist/async_queue.cjs +80 -0
  2. package/dist/async_queue.cjs.map +1 -0
  3. package/dist/async_queue.d.cts +30 -0
  4. package/dist/async_queue.d.ts +30 -0
  5. package/dist/async_queue.d.ts.map +1 -0
  6. package/dist/async_queue.js +56 -0
  7. package/dist/async_queue.js.map +1 -0
  8. package/dist/audio_frame.cjs +5 -0
  9. package/dist/audio_frame.cjs.map +1 -1
  10. package/dist/audio_frame.d.cts +3 -0
  11. package/dist/audio_frame.d.ts +3 -0
  12. package/dist/audio_frame.d.ts.map +1 -1
  13. package/dist/audio_frame.js +5 -0
  14. package/dist/audio_frame.js.map +1 -1
  15. package/dist/audio_mixer.cjs +281 -0
  16. package/dist/audio_mixer.cjs.map +1 -0
  17. package/dist/audio_mixer.d.cts +121 -0
  18. package/dist/audio_mixer.d.ts +121 -0
  19. package/dist/audio_mixer.d.ts.map +1 -0
  20. package/dist/audio_mixer.js +256 -0
  21. package/dist/audio_mixer.js.map +1 -0
  22. package/dist/audio_stream.cjs +18 -5
  23. package/dist/audio_stream.cjs.map +1 -1
  24. package/dist/audio_stream.d.cts +4 -3
  25. package/dist/audio_stream.d.ts +4 -3
  26. package/dist/audio_stream.d.ts.map +1 -1
  27. package/dist/audio_stream.js +18 -5
  28. package/dist/audio_stream.js.map +1 -1
  29. package/dist/data_streams/stream_reader.cjs.map +1 -1
  30. package/dist/data_streams/stream_reader.js.map +1 -1
  31. package/dist/frame_processor.cjs +38 -0
  32. package/dist/frame_processor.cjs.map +1 -0
  33. package/dist/frame_processor.d.cts +29 -0
  34. package/dist/frame_processor.d.ts +29 -0
  35. package/dist/frame_processor.d.ts.map +1 -0
  36. package/dist/frame_processor.js +14 -0
  37. package/dist/frame_processor.js.map +1 -0
  38. package/dist/index.cjs +6 -0
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +3 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +6 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/participant.cjs +4 -4
  46. package/dist/participant.cjs.map +1 -1
  47. package/dist/participant.d.cts +2 -2
  48. package/dist/participant.d.ts +2 -2
  49. package/dist/participant.d.ts.map +1 -1
  50. package/dist/participant.js +4 -4
  51. package/dist/participant.js.map +1 -1
  52. package/dist/proto/audio_frame_pb.cjs.map +1 -1
  53. package/dist/proto/audio_frame_pb.js.map +1 -1
  54. package/dist/proto/e2ee_pb.cjs.map +1 -1
  55. package/dist/proto/e2ee_pb.js.map +1 -1
  56. package/dist/proto/ffi_pb.cjs +4 -2
  57. package/dist/proto/ffi_pb.cjs.map +1 -1
  58. package/dist/proto/ffi_pb.d.cts +13 -1
  59. package/dist/proto/ffi_pb.d.ts +13 -1
  60. package/dist/proto/ffi_pb.d.ts.map +1 -1
  61. package/dist/proto/ffi_pb.js +5 -3
  62. package/dist/proto/ffi_pb.js.map +1 -1
  63. package/dist/proto/handle_pb.cjs.map +1 -1
  64. package/dist/proto/handle_pb.js.map +1 -1
  65. package/dist/proto/participant_pb.cjs +26 -4
  66. package/dist/proto/participant_pb.cjs.map +1 -1
  67. package/dist/proto/participant_pb.d.cts +31 -2
  68. package/dist/proto/participant_pb.d.ts +31 -2
  69. package/dist/proto/participant_pb.d.ts.map +1 -1
  70. package/dist/proto/participant_pb.js +24 -3
  71. package/dist/proto/participant_pb.js.map +1 -1
  72. package/dist/proto/room_pb.cjs +29 -2
  73. package/dist/proto/room_pb.cjs.map +1 -1
  74. package/dist/proto/room_pb.d.cts +30 -7
  75. package/dist/proto/room_pb.d.ts +30 -7
  76. package/dist/proto/room_pb.d.ts.map +1 -1
  77. package/dist/proto/room_pb.js +28 -2
  78. package/dist/proto/room_pb.js.map +1 -1
  79. package/dist/proto/rpc_pb.cjs.map +1 -1
  80. package/dist/proto/rpc_pb.js.map +1 -1
  81. package/dist/proto/stats_pb.cjs.map +1 -1
  82. package/dist/proto/stats_pb.js.map +1 -1
  83. package/dist/proto/track_pb.cjs.map +1 -1
  84. package/dist/proto/track_pb.js.map +1 -1
  85. package/dist/proto/track_publication_pb.cjs +66 -2
  86. package/dist/proto/track_publication_pb.cjs.map +1 -1
  87. package/dist/proto/track_publication_pb.d.cts +56 -1
  88. package/dist/proto/track_publication_pb.d.ts +56 -1
  89. package/dist/proto/track_publication_pb.d.ts.map +1 -1
  90. package/dist/proto/track_publication_pb.js +62 -1
  91. package/dist/proto/track_publication_pb.js.map +1 -1
  92. package/dist/proto/video_frame_pb.cjs +3 -1
  93. package/dist/proto/video_frame_pb.cjs.map +1 -1
  94. package/dist/proto/video_frame_pb.d.cts +5 -1
  95. package/dist/proto/video_frame_pb.d.ts +5 -1
  96. package/dist/proto/video_frame_pb.d.ts.map +1 -1
  97. package/dist/proto/video_frame_pb.js +3 -1
  98. package/dist/proto/video_frame_pb.js.map +1 -1
  99. package/dist/room.cjs +286 -288
  100. package/dist/room.cjs.map +1 -1
  101. package/dist/room.d.cts +11 -11
  102. package/dist/room.d.ts +11 -11
  103. package/dist/room.d.ts.map +1 -1
  104. package/dist/room.js +287 -289
  105. package/dist/room.js.map +1 -1
  106. package/dist/version.cjs +1 -1
  107. package/dist/version.cjs.map +1 -1
  108. package/dist/version.d.cts +1 -1
  109. package/dist/version.d.ts +1 -1
  110. package/dist/version.js +1 -1
  111. package/dist/version.js.map +1 -1
  112. package/package.json +9 -8
  113. package/src/async_queue.test.ts +250 -0
  114. package/src/async_queue.ts +80 -0
  115. package/src/audio_frame.ts +7 -0
  116. package/src/audio_mixer.test.ts +167 -0
  117. package/src/audio_mixer.ts +407 -0
  118. package/src/audio_stream.ts +22 -7
  119. package/src/data_streams/stream_reader.ts +4 -4
  120. package/src/frame_processor.ts +29 -0
  121. package/src/index.ts +6 -0
  122. package/src/participant.ts +5 -5
  123. package/src/proto/audio_frame_pb.ts +1 -1
  124. package/src/proto/e2ee_pb.ts +1 -1
  125. package/src/proto/ffi_pb.ts +16 -2
  126. package/src/proto/handle_pb.ts +1 -1
  127. package/src/proto/participant_pb.ts +45 -1
  128. package/src/proto/room_pb.ts +52 -8
  129. package/src/proto/rpc_pb.ts +1 -1
  130. package/src/proto/stats_pb.ts +1 -1
  131. package/src/proto/track_pb.ts +1 -1
  132. package/src/proto/track_publication_pb.ts +105 -1
  133. package/src/proto/video_frame_pb.ts +7 -1
  134. package/src/room.ts +297 -300
  135. package/src/version.ts +1 -1
package/src/room.ts CHANGED
@@ -18,7 +18,7 @@ import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
18
18
  import { log } from './log.js';
19
19
  import type { Participant } from './participant.js';
20
20
  import { LocalParticipant, RemoteParticipant } from './participant.js';
21
- import { EncryptionState, EncryptionType } from './proto/e2ee_pb.js';
21
+ import { EncryptionState, type EncryptionType } from './proto/e2ee_pb.js';
22
22
  import type { FfiEvent } from './proto/ffi_pb.js';
23
23
  import type { DisconnectReason, OwnedParticipant } from './proto/participant_pb.js';
24
24
  import type { DataStream_Trailer, DisconnectCallback } from './proto/room_pb.js';
@@ -87,7 +87,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
87
87
  * the local participant to acquire the lock while doing state updates related to FFI events
88
88
  * before processing the next events
89
89
  */
90
- private roomEventLock = new Mutex();
90
+ private ffiEventLock = new Mutex();
91
91
 
92
92
  private byteStreamControllers = new Map<string, StreamController<DataStream_Chunk>>();
93
93
  private textStreamControllers = new Map<string, StreamController<DataStream_Chunk>>();
@@ -179,10 +179,10 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
179
179
 
180
180
  /**
181
181
  * Connects to a LiveKit room using the provided URL and access token.
182
- * @param url The WebSocket URL of the LiveKit server
183
- * @param token A valid LiveKit access token for authentication
184
- * @param opts Optional room configuration options
185
- * @throws ConnectError if connection fails
182
+ * @param url - The WebSocket URL of the LiveKit server
183
+ * @param token - A valid LiveKit access token for authentication
184
+ * @param opts - Optional room configuration options
185
+ * @throws ConnectError - if connection fails
186
186
  */
187
187
  async connect(url: string, token: string, opts?: RoomOptions) {
188
188
  const options = { ...defaultRoomOptions, ...opts };
@@ -221,7 +221,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
221
221
  this.connectionState = ConnectionState.CONN_CONNECTED;
222
222
  this.localParticipant = new LocalParticipant(
223
223
  cb.message.value.localParticipant!,
224
- this.roomEventLock,
224
+ this.ffiEventLock,
225
225
  );
226
226
 
227
227
  for (const pt of cb.message.value.participants) {
@@ -258,7 +258,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
258
258
  });
259
259
 
260
260
  await FfiClient.instance.waitFor<DisconnectCallback>((ev: FfiEvent) => {
261
- return ev.message.case == 'connect' && ev.message.value.asyncId == res.asyncId;
261
+ return ev.message.case == 'disconnect' && ev.message.value.asyncId == res.asyncId;
262
262
  });
263
263
 
264
264
  FfiClient.instance.removeListener(FfiClientEvent.FfiEvent, this.onFfiEvent);
@@ -268,9 +268,9 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
268
268
  /**
269
269
  * Registers a handler for incoming text data streams on a specific topic.
270
270
  * Text streams are used for receiving structured text data from other participants.
271
- * @param topic The topic to listen for text streams on
272
- * @param callback Function to handle incoming text stream data
273
- * @throws Error if a handler for this topic is already registered
271
+ * @param topic - The topic to listen for text streams on
272
+ * @param callback - Function to handle incoming text stream data
273
+ * @throws Error - if a handler for this topic is already registered
274
274
  */
275
275
  registerTextStreamHandler(topic: string, callback: TextStreamHandler) {
276
276
  if (this.textStreamHandlers.has(topic)) {
@@ -286,9 +286,9 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
286
286
  /**
287
287
  * Registers a handler for incoming byte data streams on a specific topic.
288
288
  * Byte streams are used for receiving binary data like files from other participants.
289
- * @param topic The topic to listen for byte streams on
290
- * @param callback Function to handle incoming byte stream data
291
- * @throws Error if a handler for this topic is already registered
289
+ * @param topic - The topic to listen for byte streams on
290
+ * @param callback - Function to handle incoming byte stream data
291
+ * @throws Error - if a handler for this topic is already registered
292
292
  */
293
293
  registerByteStreamHandler(topic: string, callback: ByteStreamHandler) {
294
294
  if (this.byteStreamHandlers.has(topic)) {
@@ -302,18 +302,23 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
302
302
  }
303
303
 
304
304
  private onFfiEvent = async (ffiEvent: FfiEvent) => {
305
- if (!this.localParticipant || !this.ffiHandle || !this.info) {
306
- this.preConnectEvents.push(ffiEvent);
307
- return;
308
- }
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
+ }
309
311
 
310
- // process preConnectEvents if we received the connectCallback after the events were queued
311
- for (const ev of this.preConnectEvents) {
312
- await this.processFfiEvent(ev);
313
- }
314
- 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 = [];
315
317
 
316
- await this.processFfiEvent(ffiEvent);
318
+ await this.processFfiEvent(ffiEvent);
319
+ } finally {
320
+ unlock();
321
+ }
317
322
  };
318
323
 
319
324
  private processFfiEvent = async (ffiEvent: FfiEvent) => {
@@ -321,302 +326,294 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
321
326
  throw new Error('processFfiEvent called before connect');
322
327
  }
323
328
 
324
- const unlock = await this.roomEventLock.lock();
325
-
326
- try {
327
- if (ffiEvent.message.case == 'rpcMethodInvocation') {
328
- if (
329
- ffiEvent.message.value.localParticipantHandle == this.localParticipant.ffi_handle.handle
330
- ) {
331
- this.localParticipant.handleRpcMethodInvocation(
332
- ffiEvent.message.value.invocationId!,
333
- ffiEvent.message.value.method!,
334
- ffiEvent.message.value.requestId!,
335
- ffiEvent.message.value.callerIdentity!,
336
- ffiEvent.message.value.payload!,
337
- ffiEvent.message.value.responseTimeoutMs!,
338
- );
339
- }
340
- return;
341
- } else if (
342
- ffiEvent.message.case != 'roomEvent' ||
343
- ffiEvent.message.value.roomHandle != this.ffiHandle.handle
329
+ if (ffiEvent.message.case == 'rpcMethodInvocation') {
330
+ if (
331
+ ffiEvent.message.value.localParticipantHandle == this.localParticipant.ffi_handle.handle
344
332
  ) {
345
- return;
333
+ this.localParticipant.handleRpcMethodInvocation(
334
+ ffiEvent.message.value.invocationId!,
335
+ ffiEvent.message.value.method!,
336
+ ffiEvent.message.value.requestId!,
337
+ ffiEvent.message.value.callerIdentity!,
338
+ ffiEvent.message.value.payload!,
339
+ ffiEvent.message.value.responseTimeoutMs!,
340
+ );
346
341
  }
342
+ return;
343
+ } else if (
344
+ ffiEvent.message.case != 'roomEvent' ||
345
+ ffiEvent.message.value.roomHandle != this.ffiHandle.handle
346
+ ) {
347
+ return;
348
+ }
347
349
 
348
- const ev = ffiEvent.message.value.message;
349
- if (process.env.LIVEKIT_DEBUG_LOG_ROOM_EVENTS) {
350
- console.log('Room event:', ev);
350
+ const ev = ffiEvent.message.value.message;
351
+ if (process.env.LIVEKIT_DEBUG_LOG_ROOM_EVENTS) {
352
+ console.log('Room event:', ev);
353
+ }
354
+ if (ev.case == 'participantConnected') {
355
+ const participant = this.createRemoteParticipant(ev.value.info!);
356
+ this.remoteParticipants.set(participant.identity!, participant);
357
+ this.emit(RoomEvent.ParticipantConnected, participant);
358
+ } else if (ev.case == 'participantDisconnected') {
359
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
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`);
351
366
  }
352
- if (ev.case == 'participantConnected') {
353
- const participant = this.createRemoteParticipant(ev.value.info!);
354
- this.remoteParticipants.set(participant.identity!, participant);
355
- this.emit(RoomEvent.ParticipantConnected, participant);
356
- } else if (ev.case == 'participantDisconnected') {
357
- const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
358
- if (participant) {
359
- this.remoteParticipants.delete(participant.identity);
360
- participant.info.disconnectReason = ev.value.disconnectReason;
361
- this.emit(RoomEvent.ParticipantDisconnected, participant);
362
- } else {
363
- console.log(`RoomEvent.ParticipantDisconnected: Could not find participant`);
364
- }
365
- } else if (ev.case == 'localTrackPublished') {
366
- const publication = this.localParticipant.trackPublications.get(ev.value.trackSid!);
367
- this.emit(RoomEvent.LocalTrackPublished, publication!, this.localParticipant);
368
- } else if (ev.case == 'localTrackUnpublished') {
369
- const publication = this.localParticipant.trackPublications.get(ev.value.publicationSid!);
370
- this.localParticipant.trackPublications.delete(ev.value.publicationSid!);
371
- this.emit(RoomEvent.LocalTrackUnpublished, publication!, this.localParticipant!);
372
- } else if (ev.case == 'localTrackSubscribed') {
373
- const publication = this.localParticipant.trackPublications.get(ev.value.trackSid!);
374
- if (publication) {
375
- publication.resolveFirstSubscription();
376
- this.emit(RoomEvent.LocalTrackSubscribed, publication!.track!);
377
- } else {
378
- console.warn(
379
- `RoomEvent.LocalTrackSubscribed: Publication not found: ${ev.value.trackSid}`,
380
- );
381
- }
382
- } else if (ev.case == 'trackPublished') {
383
- const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
384
- const publication = new RemoteTrackPublication(ev.value.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
- }
392
- this.emit(RoomEvent.TrackPublished, publication, participant!);
393
- } else if (ev.case == 'trackUnpublished') {
394
- const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
395
- const publication = participant.trackPublications.get(ev.value.publicationSid!);
396
- participant.trackPublications.delete(ev.value.publicationSid!);
397
- if (publication) {
398
- this.emit(RoomEvent.TrackUnpublished, publication, participant);
399
- } else {
400
- console.warn(`RoomEvent.TrackUnpublished: Could not find publication`);
367
+ } else if (ev.case == 'localTrackPublished') {
368
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid!);
369
+ this.emit(RoomEvent.LocalTrackPublished, publication!, this.localParticipant);
370
+ } else if (ev.case == 'localTrackUnpublished') {
371
+ const publication = this.localParticipant.trackPublications.get(ev.value.publicationSid!);
372
+ this.localParticipant.trackPublications.delete(ev.value.publicationSid!);
373
+ this.emit(RoomEvent.LocalTrackUnpublished, publication!, this.localParticipant!);
374
+ } else if (ev.case == 'localTrackSubscribed') {
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
+ }
382
+ } else if (ev.case == 'trackPublished') {
383
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
384
+ const publication = new RemoteTrackPublication(ev.value.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
+ }
392
+ this.emit(RoomEvent.TrackPublished, publication, participant!);
393
+ } else if (ev.case == 'trackUnpublished') {
394
+ const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
395
+ const publication = participant.trackPublications.get(ev.value.publicationSid!);
396
+ participant.trackPublications.delete(ev.value.publicationSid!);
397
+ if (publication) {
398
+ this.emit(RoomEvent.TrackUnpublished, publication, participant);
399
+ } else {
400
+ console.warn(`RoomEvent.TrackUnpublished: Could not find publication`);
401
+ }
402
+ } else if (ev.case == 'trackSubscribed') {
403
+ const ownedTrack = ev.value.track!;
404
+ const trackInfo = ownedTrack.info!;
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);
401
415
  }
402
- } else if (ev.case == 'trackSubscribed') {
403
- const ownedTrack = ev.value.track!;
404
- const trackInfo = ownedTrack.info!;
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
- }
416
416
 
417
- this.emit(RoomEvent.TrackSubscribed, publication.track!, publication, participant);
418
- } catch (e: any) {
419
- console.warn(`RoomEvent.TrackSubscribed: ${e.message}`);
420
- }
421
- } else if (ev.case == 'trackUnsubscribed') {
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
- }
434
- } else if (ev.case == 'trackSubscriptionFailed') {
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
- }
446
- } else if (ev.case == 'trackMuted') {
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}`);
459
- }
460
- } else if (ev.case == 'trackUnmuted') {
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}`);
473
- }
474
- } else if (ev.case == 'activeSpeakersChanged') {
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
- }
483
- } else if (ev.case == 'roomMetadataChanged') {
484
- this.info.metadata = ev.value.metadata ?? '';
485
- this.emit(RoomEvent.RoomMetadataChanged, this.info.metadata);
486
- } else if (ev.case == 'participantMetadataChanged') {
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}`);
417
+ this.emit(RoomEvent.TrackSubscribed, publication.track!, publication, participant);
418
+ } catch (e: unknown) {
419
+ console.warn(`RoomEvent.TrackSubscribed: ${(e as Error).message}`);
420
+ }
421
+ } else if (ev.case == 'trackUnsubscribed') {
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: unknown) {
432
+ console.warn(`RoomEvent.TrackUnsubscribed: ${(e as Error).message}`);
433
+ }
434
+ } else if (ev.case == 'trackSubscriptionFailed') {
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: unknown) {
444
+ console.warn(`RoomEvent.TrackSubscriptionFailed: ${(e as Error).message}`);
445
+ }
446
+ } else if (ev.case == 'trackMuted') {
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;
493
455
  }
494
- } else if (ev.case == 'participantNameChanged') {
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}`);
456
+ this.emit(RoomEvent.TrackMuted, publication, participant);
457
+ } catch (e: unknown) {
458
+ console.warn(`RoomEvent.TrackMuted: ${(e as Error).message}`);
459
+ }
460
+ } else if (ev.case == 'trackUnmuted') {
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;
501
469
  }
502
- } else if (ev.case == 'participantAttributesChanged') {
503
- try {
504
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
505
- participant.info.attributes = ev.value.attributes.reduce(
470
+ this.emit(RoomEvent.TrackUnmuted, publication, participant);
471
+ } catch (e: unknown) {
472
+ console.warn(`RoomEvent.TrackUnmuted: ${(e as Error).message}`);
473
+ }
474
+ } else if (ev.case == 'activeSpeakersChanged') {
475
+ try {
476
+ const activeSpeakers = ev.value.participantIdentities.map((identity) =>
477
+ this.requireParticipantByIdentity(identity),
478
+ );
479
+ this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
480
+ } catch (e: unknown) {
481
+ console.warn(`RoomEvent.ActiveSpeakersChanged: ${(e as Error).message}`);
482
+ }
483
+ } else if (ev.case == 'roomMetadataChanged') {
484
+ this.info.metadata = ev.value.metadata ?? '';
485
+ this.emit(RoomEvent.RoomMetadataChanged, this.info.metadata);
486
+ } else if (ev.case == 'participantMetadataChanged') {
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: unknown) {
492
+ console.warn(`RoomEvent.ParticipantMetadataChanged: ${(e as Error).message}`);
493
+ }
494
+ } else if (ev.case == 'participantNameChanged') {
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: unknown) {
500
+ console.warn(`RoomEvent.ParticipantNameChanged: ${(e as Error).message}`);
501
+ }
502
+ } else if (ev.case == 'participantAttributesChanged') {
503
+ try {
504
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
505
+ participant.info.attributes = ev.value.attributes.reduce(
506
+ (acc, value) => {
507
+ acc[value.key!] = value.value!;
508
+ return acc;
509
+ },
510
+ {} as Record<string, string>,
511
+ );
512
+ if (Object.keys(ev.value.changedAttributes).length > 0) {
513
+ const changedAttributes = ev.value.changedAttributes.reduce(
506
514
  (acc, value) => {
507
515
  acc[value.key!] = value.value!;
508
516
  return acc;
509
517
  },
510
518
  {} as Record<string, string>,
511
519
  );
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}`);
524
- }
525
- } else if (ev.case == 'connectionQualityChanged') {
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
- }
532
- } else if (ev.case == 'chatMessage') {
533
- const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity!);
534
- const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message!;
535
- const message: ChatMessage = {
536
- id: id!,
537
- message: messageText!,
538
- timestamp: Number(timestamp),
539
- editTimestamp: Number(editTimestamp),
540
- generated,
541
- };
542
- this.emit(RoomEvent.ChatMessage, message, participant);
543
- } else if (ev.case == 'dataPacketReceived') {
544
- // Can be undefined if the data is sent from a Server SDK
545
- const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
546
- const dataPacket = ev.value.value;
547
- switch (dataPacket.case) {
548
- case 'user':
549
- const buffer = FfiClient.instance.copyBuffer(
550
- dataPacket.value.data!.data!.dataPtr!,
551
- Number(dataPacket.value.data!.data!.dataLen),
552
- );
553
- new FfiHandle(dataPacket.value.data!.handle!.id!).dispose();
554
- this.emit(
555
- RoomEvent.DataReceived,
556
- buffer,
557
- participant,
558
- ev.value.kind,
559
- dataPacket.value.topic,
560
- );
561
- break;
562
- case 'sipDtmf':
563
- const { code, digit } = dataPacket.value;
564
- this.emit(RoomEvent.DtmfReceived, code!, digit!, participant!);
565
- break;
566
- default:
567
- break;
568
- }
569
- } else if (ev.case == 'e2eeStateChanged') {
570
- if (ev.value.state == EncryptionState.INTERNAL_ERROR) {
571
- // throw generic error until Rust SDK is updated to supply the error alongside INTERNAL_ERROR
572
- this.emit(RoomEvent.EncryptionError, new Error('internal server error'));
520
+ this.emit(RoomEvent.ParticipantAttributesChanged, changedAttributes, participant);
573
521
  }
574
- } else if (ev.case == 'connectionStateChanged') {
575
- this.connectionState = ev.value.state!;
576
- this.emit(RoomEvent.ConnectionStateChanged, this.connectionState);
577
- /*} else if (ev.case == 'connected') {
578
- this.emit(RoomEvent.Connected);*/
579
- } else if (ev.case == 'disconnected') {
580
- this.emit(RoomEvent.Disconnected, ev.value.reason!);
581
- } else if (ev.case == 'reconnecting') {
582
- this.emit(RoomEvent.Reconnecting);
583
- } else if (ev.case == 'reconnected') {
584
- this.emit(RoomEvent.Reconnected);
585
- } else if (ev.case == 'roomSidChanged') {
586
- this.emit(RoomEvent.RoomSidChanged, ev.value.sid!);
587
- } else if (ev.case === 'streamHeaderReceived' && ev.value.header) {
588
- this.handleStreamHeader(ev.value.header, ev.value.participantIdentity!);
589
- } else if (ev.case === 'streamChunkReceived' && ev.value.chunk) {
590
- this.handleStreamChunk(ev.value.chunk);
591
- } else if (ev.case === 'streamTrailerReceived' && ev.value.trailer) {
592
- this.handleStreamTrailer(ev.value.trailer);
593
- } else if (ev.case === 'roomUpdated') {
594
- this.info = ev.value;
595
- this.emit(RoomEvent.RoomUpdated);
596
- } else if (ev.case === 'moved') {
597
- this.info = ev.value;
598
- this.emit(RoomEvent.Moved);
599
- } else if (ev.case === 'participantsUpdated') {
600
- for (const info of ev.value.participants) {
601
- const participant = this.retrieveParticipantByIdentity(info.identity!);
602
- if (participant) {
603
- participant.info = info;
604
- }
605
- }
606
- } else if (ev.case === 'participantEncryptionStatusChanged') {
607
- try {
608
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
522
+ } catch (e: unknown) {
523
+ console.warn(`RoomEvent.ParticipantAttributesChanged: ${(e as Error).message}`);
524
+ }
525
+ } else if (ev.case == 'connectionQualityChanged') {
526
+ try {
527
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
528
+ this.emit(RoomEvent.ConnectionQualityChanged, ev.value.quality!, participant);
529
+ } catch (e: unknown) {
530
+ console.warn(`RoomEvent.ConnectionQualityChanged: ${(e as Error).message}`);
531
+ }
532
+ } else if (ev.case == 'chatMessage') {
533
+ const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity!);
534
+ const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message!;
535
+ const message: ChatMessage = {
536
+ id: id!,
537
+ message: messageText!,
538
+ timestamp: Number(timestamp),
539
+ editTimestamp: Number(editTimestamp),
540
+ generated,
541
+ };
542
+ this.emit(RoomEvent.ChatMessage, message, participant);
543
+ } else if (ev.case == 'dataPacketReceived') {
544
+ // Can be undefined if the data is sent from a Server SDK
545
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
546
+ const dataPacket = ev.value.value;
547
+ switch (dataPacket.case) {
548
+ case 'user':
549
+ const buffer = FfiClient.instance.copyBuffer(
550
+ dataPacket.value.data!.data!.dataPtr!,
551
+ Number(dataPacket.value.data!.data!.dataLen),
552
+ );
553
+ new FfiHandle(dataPacket.value.data!.handle!.id!).dispose();
609
554
  this.emit(
610
- RoomEvent.ParticipantEncryptionStatusChanged,
611
- !!ev.value.isEncrypted,
555
+ RoomEvent.DataReceived,
556
+ buffer,
612
557
  participant,
558
+ ev.value.kind,
559
+ dataPacket.value.topic,
613
560
  );
614
- } catch (e: any) {
615
- console.warn(`RoomEvent.ParticipantEncryptionStatusChanged: ${e.message}`);
561
+ break;
562
+ case 'sipDtmf':
563
+ const { code, digit } = dataPacket.value;
564
+ this.emit(RoomEvent.DtmfReceived, code!, digit!, participant!);
565
+ break;
566
+ default:
567
+ break;
568
+ }
569
+ } else if (ev.case == 'e2eeStateChanged') {
570
+ if (ev.value.state == EncryptionState.INTERNAL_ERROR) {
571
+ // throw generic error until Rust SDK is updated to supply the error alongside INTERNAL_ERROR
572
+ this.emit(RoomEvent.EncryptionError, new Error('internal server error'));
573
+ }
574
+ } else if (ev.case == 'connectionStateChanged') {
575
+ this.connectionState = ev.value.state!;
576
+ this.emit(RoomEvent.ConnectionStateChanged, this.connectionState);
577
+ /*} else if (ev.case == 'connected') {
578
+ this.emit(RoomEvent.Connected);*/
579
+ } else if (ev.case == 'disconnected') {
580
+ this.emit(RoomEvent.Disconnected, ev.value.reason!);
581
+ } else if (ev.case == 'reconnecting') {
582
+ this.emit(RoomEvent.Reconnecting);
583
+ } else if (ev.case == 'reconnected') {
584
+ this.emit(RoomEvent.Reconnected);
585
+ } else if (ev.case == 'roomSidChanged') {
586
+ this.emit(RoomEvent.RoomSidChanged, ev.value.sid!);
587
+ } else if (ev.case === 'streamHeaderReceived' && ev.value.header) {
588
+ this.handleStreamHeader(ev.value.header, ev.value.participantIdentity!);
589
+ } else if (ev.case === 'streamChunkReceived' && ev.value.chunk) {
590
+ this.handleStreamChunk(ev.value.chunk);
591
+ } else if (ev.case === 'streamTrailerReceived' && ev.value.trailer) {
592
+ this.handleStreamTrailer(ev.value.trailer);
593
+ } else if (ev.case === 'roomUpdated') {
594
+ this.info = ev.value;
595
+ this.emit(RoomEvent.RoomUpdated);
596
+ } else if (ev.case === 'moved') {
597
+ this.info = ev.value;
598
+ this.emit(RoomEvent.Moved);
599
+ } else if (ev.case === 'participantsUpdated') {
600
+ for (const info of ev.value.participants) {
601
+ const participant = this.retrieveParticipantByIdentity(info.identity!);
602
+ if (participant) {
603
+ participant.info = info;
616
604
  }
617
605
  }
618
- } finally {
619
- unlock();
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: unknown) {
615
+ console.warn(`RoomEvent.ParticipantEncryptionStatusChanged: ${(e as Error).message}`);
616
+ }
620
617
  }
621
618
  };
622
619