@livekit/rtc-node 0.13.19 → 0.13.21

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 (57) hide show
  1. package/Cargo.toml +6 -3
  2. package/dist/audio_source.cjs +1 -0
  3. package/dist/audio_source.cjs.map +1 -1
  4. package/dist/audio_source.d.ts.map +1 -1
  5. package/dist/audio_source.js +1 -0
  6. package/dist/audio_source.js.map +1 -1
  7. package/dist/index.d.cts +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/participant.cjs +43 -32
  10. package/dist/participant.cjs.map +1 -1
  11. package/dist/participant.d.cts +3 -0
  12. package/dist/participant.d.ts +3 -0
  13. package/dist/participant.d.ts.map +1 -1
  14. package/dist/participant.js +43 -32
  15. package/dist/participant.js.map +1 -1
  16. package/dist/proto/data_stream_pb.cjs +91 -2
  17. package/dist/proto/data_stream_pb.cjs.map +1 -1
  18. package/dist/proto/data_stream_pb.d.cts +92 -1
  19. package/dist/proto/data_stream_pb.d.ts +92 -1
  20. package/dist/proto/data_stream_pb.d.ts.map +1 -1
  21. package/dist/proto/data_stream_pb.js +88 -2
  22. package/dist/proto/data_stream_pb.js.map +1 -1
  23. package/dist/proto/ffi_pb.cjs +6 -3
  24. package/dist/proto/ffi_pb.cjs.map +1 -1
  25. package/dist/proto/ffi_pb.d.cts +19 -1
  26. package/dist/proto/ffi_pb.d.ts +19 -1
  27. package/dist/proto/ffi_pb.d.ts.map +1 -1
  28. package/dist/proto/ffi_pb.js +7 -4
  29. package/dist/proto/ffi_pb.js.map +1 -1
  30. package/dist/proto/room_pb.cjs +32 -2
  31. package/dist/proto/room_pb.cjs.map +1 -1
  32. package/dist/proto/room_pb.d.cts +38 -2
  33. package/dist/proto/room_pb.d.ts +38 -2
  34. package/dist/proto/room_pb.d.ts.map +1 -1
  35. package/dist/proto/room_pb.js +31 -2
  36. package/dist/proto/room_pb.js.map +1 -1
  37. package/dist/room.cjs +300 -205
  38. package/dist/room.cjs.map +1 -1
  39. package/dist/room.d.cts +16 -3
  40. package/dist/room.d.ts +16 -3
  41. package/dist/room.d.ts.map +1 -1
  42. package/dist/room.js +301 -206
  43. package/dist/room.js.map +1 -1
  44. package/dist/version.cjs +1 -1
  45. package/dist/version.cjs.map +1 -1
  46. package/dist/version.d.cts +1 -1
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/dist/version.js.map +1 -1
  50. package/package.json +6 -6
  51. package/src/audio_source.ts +1 -0
  52. package/src/participant.ts +48 -30
  53. package/src/proto/data_stream_pb.ts +159 -0
  54. package/src/proto/ffi_pb.ts +22 -1
  55. package/src/proto/room_pb.ts +64 -1
  56. package/src/room.ts +319 -214
  57. package/src/version.ts +1 -1
package/dist/room.js CHANGED
@@ -1,10 +1,11 @@
1
+ import { Mutex } from "@livekit/mutex";
1
2
  import EventEmitter from "events";
2
3
  import { ByteStreamReader, TextStreamReader } from "./data_streams/stream_reader.js";
3
4
  import { E2EEManager, defaultE2EEOptions } from "./e2ee.js";
4
5
  import { FfiClient, FfiClientEvent, FfiHandle } from "./ffi_client.js";
5
6
  import { log } from "./log.js";
6
7
  import { LocalParticipant, RemoteParticipant } from "./participant.js";
7
- import { EncryptionState } from "./proto/e2ee_pb.js";
8
+ import { EncryptionState, EncryptionType } from "./proto/e2ee_pb.js";
8
9
  import {
9
10
  ConnectRequest,
10
11
  ConnectionState,
@@ -25,6 +26,7 @@ const defaultRoomOptions = new FfiRoomOptions({
25
26
  autoSubscribe: true,
26
27
  dynacast: false,
27
28
  e2ee: void 0,
29
+ encryption: void 0,
28
30
  rtcConfig: void 0,
29
31
  adaptiveStream: false,
30
32
  joinRetries: 1
@@ -32,6 +34,12 @@ const defaultRoomOptions = new FfiRoomOptions({
32
34
  class Room extends EventEmitter {
33
35
  constructor() {
34
36
  super();
37
+ /**
38
+ * used to ensure events are processed sequentially and allow for
39
+ * the local participant to acquire the lock while doing state updates related to FFI events
40
+ * before processing the next events
41
+ */
42
+ this.roomEventLock = new Mutex();
35
43
  this.byteStreamControllers = /* @__PURE__ */ new Map();
36
44
  this.textStreamControllers = /* @__PURE__ */ new Map();
37
45
  this.byteStreamHandlers = /* @__PURE__ */ new Map();
@@ -39,226 +47,305 @@ class Room extends EventEmitter {
39
47
  this.preConnectEvents = [];
40
48
  this.connectionState = ConnectionState.CONN_DISCONNECTED;
41
49
  this.remoteParticipants = /* @__PURE__ */ new Map();
42
- this.onFfiEvent = (ffiEvent) => {
50
+ this.onFfiEvent = async (ffiEvent) => {
43
51
  if (!this.localParticipant || !this.ffiHandle || !this.info) {
44
52
  this.preConnectEvents.push(ffiEvent);
45
53
  return;
46
54
  }
47
55
  for (const ev of this.preConnectEvents) {
48
- this.processFfiEvent(ev);
56
+ await this.processFfiEvent(ev);
49
57
  }
50
58
  this.preConnectEvents = [];
51
- this.processFfiEvent(ffiEvent);
59
+ await this.processFfiEvent(ffiEvent);
52
60
  };
53
- this.processFfiEvent = (ffiEvent) => {
61
+ this.processFfiEvent = async (ffiEvent) => {
54
62
  if (!this.localParticipant || !this.ffiHandle || !this.info) {
55
63
  throw new Error("processFfiEvent called before connect");
56
64
  }
57
- if (ffiEvent.message.case == "rpcMethodInvocation") {
58
- if (ffiEvent.message.value.localParticipantHandle == this.localParticipant.ffi_handle.handle) {
59
- this.localParticipant.handleRpcMethodInvocation(
60
- ffiEvent.message.value.invocationId,
61
- ffiEvent.message.value.method,
62
- ffiEvent.message.value.requestId,
63
- ffiEvent.message.value.callerIdentity,
64
- ffiEvent.message.value.payload,
65
- ffiEvent.message.value.responseTimeoutMs
66
- );
67
- }
68
- return;
69
- } else if (ffiEvent.message.case != "roomEvent" || ffiEvent.message.value.roomHandle != this.ffiHandle.handle) {
70
- return;
71
- }
72
- const ev = ffiEvent.message.value.message;
73
- if (process.env.LIVEKIT_DEBUG_LOG_ROOM_EVENTS) {
74
- console.log("Room event:", ev);
75
- }
76
- if (ev.case == "participantConnected") {
77
- const participant = this.createRemoteParticipant(ev.value.info);
78
- this.remoteParticipants.set(participant.identity, participant);
79
- this.emit("participantConnected" /* ParticipantConnected */, participant);
80
- } else if (ev.case == "participantDisconnected") {
81
- const participant = this.remoteParticipants.get(ev.value.participantIdentity);
82
- this.remoteParticipants.delete(participant.identity);
83
- participant.info.disconnectReason = ev.value.disconnectReason;
84
- this.emit("participantDisconnected" /* ParticipantDisconnected */, participant);
85
- } else if (ev.case == "localTrackPublished") {
86
- const publication = this.localParticipant.trackPublications.get(ev.value.trackSid);
87
- this.emit("localTrackPublished" /* LocalTrackPublished */, publication, this.localParticipant);
88
- } else if (ev.case == "localTrackUnpublished") {
89
- const publication = this.localParticipant.trackPublications.get(ev.value.publicationSid);
90
- this.localParticipant.trackPublications.delete(ev.value.publicationSid);
91
- this.emit("localTrackUnpublished" /* LocalTrackUnpublished */, publication, this.localParticipant);
92
- } else if (ev.case == "localTrackSubscribed") {
93
- const publication = this.localParticipant.trackPublications.get(ev.value.trackSid);
94
- publication.resolveFirstSubscription();
95
- this.emit("localTrackSubscribed" /* LocalTrackSubscribed */, publication.track);
96
- } else if (ev.case == "trackPublished") {
97
- const participant = this.remoteParticipants.get(ev.value.participantIdentity);
98
- const publication = new RemoteTrackPublication(ev.value.publication);
99
- participant.trackPublications.set(publication.sid, publication);
100
- this.emit("trackPublished" /* TrackPublished */, publication, participant);
101
- } else if (ev.case == "trackUnpublished") {
102
- const participant = this.requireRemoteParticipant(ev.value.participantIdentity);
103
- const publication = participant.trackPublications.get(ev.value.publicationSid);
104
- participant.trackPublications.delete(ev.value.publicationSid);
105
- if (publication) {
106
- this.emit("trackUnpublished" /* TrackUnpublished */, publication, participant);
107
- }
108
- } else if (ev.case == "trackSubscribed") {
109
- const ownedTrack = ev.value.track;
110
- const trackInfo = ownedTrack.info;
111
- const { participant, publication } = this.requirePublicationOfRemoteParticipant(
112
- ev.value.participantIdentity,
113
- trackInfo.sid
114
- );
115
- publication.subscribed = true;
116
- if (trackInfo.kind == TrackKind.KIND_VIDEO) {
117
- publication.track = new RemoteVideoTrack(ownedTrack);
118
- } else if (trackInfo.kind == TrackKind.KIND_AUDIO) {
119
- publication.track = new RemoteAudioTrack(ownedTrack);
120
- }
121
- this.emit("trackSubscribed" /* TrackSubscribed */, publication.track, publication, participant);
122
- } else if (ev.case == "trackUnsubscribed") {
123
- const { participant, publication } = this.requirePublicationOfRemoteParticipant(
124
- ev.value.participantIdentity,
125
- ev.value.trackSid
126
- );
127
- const track = publication.track;
128
- publication.track = void 0;
129
- publication.subscribed = false;
130
- this.emit("trackUnsubscribed" /* TrackUnsubscribed */, track, publication, participant);
131
- } else if (ev.case == "trackSubscriptionFailed") {
132
- const participant = this.requireRemoteParticipant(ev.value.participantIdentity);
133
- this.emit("trackSubscriptionFailed" /* TrackSubscriptionFailed */, ev.value.trackSid, participant, ev.value.error);
134
- } else if (ev.case == "trackMuted") {
135
- const { participant, publication } = this.requirePublicationOfParticipant(
136
- ev.value.participantIdentity,
137
- ev.value.trackSid
138
- );
139
- publication.info.muted = true;
140
- if (publication.track) {
141
- publication.track.info.muted = true;
142
- }
143
- this.emit("trackMuted" /* TrackMuted */, publication, participant);
144
- } else if (ev.case == "trackUnmuted") {
145
- const { participant, publication } = this.requirePublicationOfParticipant(
146
- ev.value.participantIdentity,
147
- ev.value.trackSid
148
- );
149
- publication.info.muted = false;
150
- if (publication.track) {
151
- publication.track.info.muted = false;
65
+ const unlock = await this.roomEventLock.lock();
66
+ try {
67
+ if (ffiEvent.message.case == "rpcMethodInvocation") {
68
+ if (ffiEvent.message.value.localParticipantHandle == this.localParticipant.ffi_handle.handle) {
69
+ this.localParticipant.handleRpcMethodInvocation(
70
+ ffiEvent.message.value.invocationId,
71
+ ffiEvent.message.value.method,
72
+ ffiEvent.message.value.requestId,
73
+ ffiEvent.message.value.callerIdentity,
74
+ ffiEvent.message.value.payload,
75
+ ffiEvent.message.value.responseTimeoutMs
76
+ );
77
+ }
78
+ return;
79
+ } else if (ffiEvent.message.case != "roomEvent" || ffiEvent.message.value.roomHandle != this.ffiHandle.handle) {
80
+ return;
152
81
  }
153
- this.emit("trackUnmuted" /* TrackUnmuted */, publication, participant);
154
- } else if (ev.case == "activeSpeakersChanged") {
155
- const activeSpeakers = ev.value.participantIdentities.map(
156
- (identity) => this.requireParticipantByIdentity(identity)
157
- );
158
- this.emit("activeSpeakersChanged" /* ActiveSpeakersChanged */, activeSpeakers);
159
- } else if (ev.case == "roomMetadataChanged") {
160
- this.info.metadata = ev.value.metadata;
161
- this.emit("roomMetadataChanged" /* RoomMetadataChanged */, this.info.metadata);
162
- } else if (ev.case == "participantMetadataChanged") {
163
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
164
- participant.info.metadata = ev.value.metadata;
165
- this.emit("participantMetadataChanged" /* ParticipantMetadataChanged */, participant.metadata, participant);
166
- } else if (ev.case == "participantNameChanged") {
167
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
168
- participant.info.name = ev.value.name;
169
- this.emit("participantNameChanged" /* ParticipantNameChanged */, participant.name, participant);
170
- } else if (ev.case == "participantAttributesChanged") {
171
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
172
- participant.info.attributes = ev.value.attributes.reduce(
173
- (acc, value) => {
174
- acc[value.key] = value.value;
175
- return acc;
176
- },
177
- {}
178
- );
179
- if (Object.keys(ev.value.changedAttributes).length > 0) {
180
- const changedAttributes = ev.value.changedAttributes.reduce(
181
- (acc, value) => {
182
- acc[value.key] = value.value;
183
- return acc;
184
- },
185
- {}
186
- );
187
- this.emit("participantAttributesChanged" /* ParticipantAttributesChanged */, changedAttributes, participant);
82
+ const ev = ffiEvent.message.value.message;
83
+ if (process.env.LIVEKIT_DEBUG_LOG_ROOM_EVENTS) {
84
+ console.log("Room event:", ev);
188
85
  }
189
- } else if (ev.case == "connectionQualityChanged") {
190
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
191
- this.emit("connectionQualityChanged" /* ConnectionQualityChanged */, ev.value.quality, participant);
192
- } else if (ev.case == "chatMessage") {
193
- const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity);
194
- const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message;
195
- const message = {
196
- id,
197
- message: messageText,
198
- timestamp: Number(timestamp),
199
- editTimestamp: Number(editTimestamp),
200
- generated
201
- };
202
- this.emit("chatMessage" /* ChatMessage */, message, participant);
203
- } else if (ev.case == "dataPacketReceived") {
204
- const participant = this.remoteParticipants.get(ev.value.participantIdentity);
205
- const dataPacket = ev.value.value;
206
- switch (dataPacket.case) {
207
- case "user":
208
- const buffer = FfiClient.instance.copyBuffer(
209
- dataPacket.value.data.data.dataPtr,
210
- Number(dataPacket.value.data.data.dataLen)
86
+ if (ev.case == "participantConnected") {
87
+ const participant = this.createRemoteParticipant(ev.value.info);
88
+ this.remoteParticipants.set(participant.identity, participant);
89
+ this.emit("participantConnected" /* ParticipantConnected */, participant);
90
+ } else if (ev.case == "participantDisconnected") {
91
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity);
92
+ if (participant) {
93
+ this.remoteParticipants.delete(participant.identity);
94
+ participant.info.disconnectReason = ev.value.disconnectReason;
95
+ this.emit("participantDisconnected" /* ParticipantDisconnected */, participant);
96
+ } else {
97
+ console.log(`RoomEvent.ParticipantDisconnected: Could not find participant`);
98
+ }
99
+ } else if (ev.case == "localTrackPublished") {
100
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid);
101
+ this.emit("localTrackPublished" /* LocalTrackPublished */, publication, this.localParticipant);
102
+ } else if (ev.case == "localTrackUnpublished") {
103
+ const publication = this.localParticipant.trackPublications.get(ev.value.publicationSid);
104
+ this.localParticipant.trackPublications.delete(ev.value.publicationSid);
105
+ this.emit("localTrackUnpublished" /* LocalTrackUnpublished */, publication, this.localParticipant);
106
+ } else if (ev.case == "localTrackSubscribed") {
107
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid);
108
+ if (publication) {
109
+ publication.resolveFirstSubscription();
110
+ this.emit("localTrackSubscribed" /* LocalTrackSubscribed */, publication.track);
111
+ } else {
112
+ console.warn(
113
+ `RoomEvent.LocalTrackSubscribed: Publication not found: ${ev.value.trackSid}`
114
+ );
115
+ }
116
+ } else if (ev.case == "trackPublished") {
117
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity);
118
+ const publication = new RemoteTrackPublication(ev.value.publication);
119
+ if (participant) {
120
+ participant.trackPublications.set(publication.sid, publication);
121
+ } else {
122
+ console.warn(
123
+ `RoomEvent.TrackPublished: Could not find participant: ${ev.value.participantIdentity}`
124
+ );
125
+ }
126
+ this.emit("trackPublished" /* TrackPublished */, publication, participant);
127
+ } else if (ev.case == "trackUnpublished") {
128
+ const participant = this.requireRemoteParticipant(ev.value.participantIdentity);
129
+ const publication = participant.trackPublications.get(ev.value.publicationSid);
130
+ participant.trackPublications.delete(ev.value.publicationSid);
131
+ if (publication) {
132
+ this.emit("trackUnpublished" /* TrackUnpublished */, publication, participant);
133
+ } else {
134
+ console.warn(`RoomEvent.TrackUnpublished: Could not find publication`);
135
+ }
136
+ } else if (ev.case == "trackSubscribed") {
137
+ const ownedTrack = ev.value.track;
138
+ const trackInfo = ownedTrack.info;
139
+ try {
140
+ const { participant, publication } = this.requirePublicationOfRemoteParticipant(
141
+ ev.value.participantIdentity,
142
+ trackInfo.sid
143
+ );
144
+ publication.subscribed = true;
145
+ if (trackInfo.kind == TrackKind.KIND_VIDEO) {
146
+ publication.track = new RemoteVideoTrack(ownedTrack);
147
+ } else if (trackInfo.kind == TrackKind.KIND_AUDIO) {
148
+ publication.track = new RemoteAudioTrack(ownedTrack);
149
+ }
150
+ this.emit("trackSubscribed" /* TrackSubscribed */, publication.track, publication, participant);
151
+ } catch (e) {
152
+ console.warn(`RoomEvent.TrackSubscribed: ${e.message}`);
153
+ }
154
+ } else if (ev.case == "trackUnsubscribed") {
155
+ try {
156
+ const { participant, publication } = this.requirePublicationOfRemoteParticipant(
157
+ ev.value.participantIdentity,
158
+ ev.value.trackSid
211
159
  );
212
- new FfiHandle(dataPacket.value.data.handle.id).dispose();
160
+ const track = publication.track;
161
+ publication.track = void 0;
162
+ publication.subscribed = false;
163
+ this.emit("trackUnsubscribed" /* TrackUnsubscribed */, track, publication, participant);
164
+ } catch (e) {
165
+ console.warn(`RoomEvent.TrackUnsubscribed: ${e.message}`);
166
+ }
167
+ } else if (ev.case == "trackSubscriptionFailed") {
168
+ try {
169
+ const participant = this.requireRemoteParticipant(ev.value.participantIdentity);
213
170
  this.emit(
214
- "dataReceived" /* DataReceived */,
215
- buffer,
171
+ "trackSubscriptionFailed" /* TrackSubscriptionFailed */,
172
+ ev.value.trackSid,
216
173
  participant,
217
- ev.value.kind,
218
- dataPacket.value.topic
174
+ ev.value.error
219
175
  );
220
- break;
221
- case "sipDtmf":
222
- const { code, digit } = dataPacket.value;
223
- this.emit("dtmfReceived" /* DtmfReceived */, code, digit, participant);
224
- break;
225
- default:
226
- break;
227
- }
228
- } else if (ev.case == "e2eeStateChanged") {
229
- if (ev.value.state == EncryptionState.INTERNAL_ERROR) {
230
- this.emit("encryptionError" /* EncryptionError */, new Error("internal server error"));
231
- }
232
- } else if (ev.case == "connectionStateChanged") {
233
- this.connectionState = ev.value.state;
234
- this.emit("connectionStateChanged" /* ConnectionStateChanged */, this.connectionState);
235
- } else if (ev.case == "disconnected") {
236
- this.emit("disconnected" /* Disconnected */, ev.value.reason);
237
- } else if (ev.case == "reconnecting") {
238
- this.emit("reconnecting" /* Reconnecting */);
239
- } else if (ev.case == "reconnected") {
240
- this.emit("reconnected" /* Reconnected */);
241
- } else if (ev.case == "roomSidChanged") {
242
- this.emit("roomSidChanged" /* RoomSidChanged */, ev.value.sid);
243
- } else if (ev.case === "streamHeaderReceived" && ev.value.header) {
244
- this.handleStreamHeader(ev.value.header, ev.value.participantIdentity);
245
- } else if (ev.case === "streamChunkReceived" && ev.value.chunk) {
246
- this.handleStreamChunk(ev.value.chunk);
247
- } else if (ev.case === "streamTrailerReceived" && ev.value.trailer) {
248
- this.handleStreamTrailer(ev.value.trailer);
249
- } else if (ev.case === "roomUpdated") {
250
- this.info = ev.value;
251
- this.emit("roomUpdated" /* RoomUpdated */);
252
- } else if (ev.case === "moved") {
253
- this.info = ev.value;
254
- this.emit("moved" /* Moved */);
255
- } else if (ev.case === "participantsUpdated") {
256
- for (const info of ev.value.participants) {
257
- const participant = this.retrieveParticipantByIdentity(info.identity);
258
- if (participant) {
259
- participant.info = info;
176
+ } catch (e) {
177
+ console.warn(`RoomEvent.TrackSubscriptionFailed: ${e.message}`);
178
+ }
179
+ } else if (ev.case == "trackMuted") {
180
+ try {
181
+ const { participant, publication } = this.requirePublicationOfParticipant(
182
+ ev.value.participantIdentity,
183
+ ev.value.trackSid
184
+ );
185
+ publication.info.muted = true;
186
+ if (publication.track) {
187
+ publication.track.info.muted = true;
188
+ }
189
+ this.emit("trackMuted" /* TrackMuted */, publication, participant);
190
+ } catch (e) {
191
+ console.warn(`RoomEvent.TrackMuted: ${e.message}`);
192
+ }
193
+ } else if (ev.case == "trackUnmuted") {
194
+ try {
195
+ const { participant, publication } = this.requirePublicationOfParticipant(
196
+ ev.value.participantIdentity,
197
+ ev.value.trackSid
198
+ );
199
+ publication.info.muted = false;
200
+ if (publication.track) {
201
+ publication.track.info.muted = false;
202
+ }
203
+ this.emit("trackUnmuted" /* TrackUnmuted */, publication, participant);
204
+ } catch (e) {
205
+ console.warn(`RoomEvent.TrackUnmuted: ${e.message}`);
206
+ }
207
+ } else if (ev.case == "activeSpeakersChanged") {
208
+ try {
209
+ const activeSpeakers = ev.value.participantIdentities.map(
210
+ (identity) => this.requireParticipantByIdentity(identity)
211
+ );
212
+ this.emit("activeSpeakersChanged" /* ActiveSpeakersChanged */, activeSpeakers);
213
+ } catch (e) {
214
+ console.warn(`RoomEvent.ActiveSpeakersChanged: ${e.message}`);
215
+ }
216
+ } else if (ev.case == "roomMetadataChanged") {
217
+ this.info.metadata = ev.value.metadata ?? "";
218
+ this.emit("roomMetadataChanged" /* RoomMetadataChanged */, this.info.metadata);
219
+ } else if (ev.case == "participantMetadataChanged") {
220
+ try {
221
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
222
+ participant.info.metadata = ev.value.metadata;
223
+ this.emit("participantMetadataChanged" /* ParticipantMetadataChanged */, participant.metadata, participant);
224
+ } catch (e) {
225
+ console.warn(`RoomEvent.ParticipantMetadataChanged: ${e.message}`);
226
+ }
227
+ } else if (ev.case == "participantNameChanged") {
228
+ try {
229
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
230
+ participant.info.name = ev.value.name;
231
+ this.emit("participantNameChanged" /* ParticipantNameChanged */, participant.name, participant);
232
+ } catch (e) {
233
+ console.warn(`RoomEvent.ParticipantNameChanged: ${e.message}`);
234
+ }
235
+ } else if (ev.case == "participantAttributesChanged") {
236
+ try {
237
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
238
+ participant.info.attributes = ev.value.attributes.reduce(
239
+ (acc, value) => {
240
+ acc[value.key] = value.value;
241
+ return acc;
242
+ },
243
+ {}
244
+ );
245
+ if (Object.keys(ev.value.changedAttributes).length > 0) {
246
+ const changedAttributes = ev.value.changedAttributes.reduce(
247
+ (acc, value) => {
248
+ acc[value.key] = value.value;
249
+ return acc;
250
+ },
251
+ {}
252
+ );
253
+ this.emit("participantAttributesChanged" /* ParticipantAttributesChanged */, changedAttributes, participant);
254
+ }
255
+ } catch (e) {
256
+ console.warn(`RoomEvent.ParticipantAttributesChanged: ${e.message}`);
257
+ }
258
+ } else if (ev.case == "connectionQualityChanged") {
259
+ try {
260
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
261
+ this.emit("connectionQualityChanged" /* ConnectionQualityChanged */, ev.value.quality, participant);
262
+ } catch (e) {
263
+ console.warn(`RoomEvent.ConnectionQualityChanged: ${e.message}`);
264
+ }
265
+ } else if (ev.case == "chatMessage") {
266
+ const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity);
267
+ const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message;
268
+ const message = {
269
+ id,
270
+ message: messageText,
271
+ timestamp: Number(timestamp),
272
+ editTimestamp: Number(editTimestamp),
273
+ generated
274
+ };
275
+ this.emit("chatMessage" /* ChatMessage */, message, participant);
276
+ } else if (ev.case == "dataPacketReceived") {
277
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity);
278
+ const dataPacket = ev.value.value;
279
+ switch (dataPacket.case) {
280
+ case "user":
281
+ const buffer = FfiClient.instance.copyBuffer(
282
+ dataPacket.value.data.data.dataPtr,
283
+ Number(dataPacket.value.data.data.dataLen)
284
+ );
285
+ new FfiHandle(dataPacket.value.data.handle.id).dispose();
286
+ this.emit(
287
+ "dataReceived" /* DataReceived */,
288
+ buffer,
289
+ participant,
290
+ ev.value.kind,
291
+ dataPacket.value.topic
292
+ );
293
+ break;
294
+ case "sipDtmf":
295
+ const { code, digit } = dataPacket.value;
296
+ this.emit("dtmfReceived" /* DtmfReceived */, code, digit, participant);
297
+ break;
298
+ default:
299
+ break;
300
+ }
301
+ } else if (ev.case == "e2eeStateChanged") {
302
+ if (ev.value.state == EncryptionState.INTERNAL_ERROR) {
303
+ this.emit("encryptionError" /* EncryptionError */, new Error("internal server error"));
304
+ }
305
+ } else if (ev.case == "connectionStateChanged") {
306
+ this.connectionState = ev.value.state;
307
+ this.emit("connectionStateChanged" /* ConnectionStateChanged */, this.connectionState);
308
+ } else if (ev.case == "disconnected") {
309
+ this.emit("disconnected" /* Disconnected */, ev.value.reason);
310
+ } else if (ev.case == "reconnecting") {
311
+ this.emit("reconnecting" /* Reconnecting */);
312
+ } else if (ev.case == "reconnected") {
313
+ this.emit("reconnected" /* Reconnected */);
314
+ } else if (ev.case == "roomSidChanged") {
315
+ this.emit("roomSidChanged" /* RoomSidChanged */, ev.value.sid);
316
+ } else if (ev.case === "streamHeaderReceived" && ev.value.header) {
317
+ this.handleStreamHeader(ev.value.header, ev.value.participantIdentity);
318
+ } else if (ev.case === "streamChunkReceived" && ev.value.chunk) {
319
+ this.handleStreamChunk(ev.value.chunk);
320
+ } else if (ev.case === "streamTrailerReceived" && ev.value.trailer) {
321
+ this.handleStreamTrailer(ev.value.trailer);
322
+ } else if (ev.case === "roomUpdated") {
323
+ this.info = ev.value;
324
+ this.emit("roomUpdated" /* RoomUpdated */);
325
+ } else if (ev.case === "moved") {
326
+ this.info = ev.value;
327
+ this.emit("moved" /* Moved */);
328
+ } else if (ev.case === "participantsUpdated") {
329
+ for (const info of ev.value.participants) {
330
+ const participant = this.retrieveParticipantByIdentity(info.identity);
331
+ if (participant) {
332
+ participant.info = info;
333
+ }
334
+ }
335
+ } else if (ev.case === "participantEncryptionStatusChanged") {
336
+ try {
337
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
338
+ this.emit(
339
+ "participantEncryptionStatusChanged" /* ParticipantEncryptionStatusChanged */,
340
+ !!ev.value.isEncrypted,
341
+ participant
342
+ );
343
+ } catch (e) {
344
+ console.warn(`RoomEvent.ParticipantEncryptionStatusChanged: ${e.message}`);
260
345
  }
261
346
  }
347
+ } finally {
348
+ unlock();
262
349
  }
263
350
  };
264
351
  }
@@ -341,7 +428,8 @@ class Room extends EventEmitter {
341
428
  */
342
429
  async connect(url, token, opts) {
343
430
  const options = { ...defaultRoomOptions, ...opts };
344
- const e2eeOptions = { ...defaultE2EEOptions, ...options.e2ee };
431
+ const e2eeEnabled = options.encryption || options.e2ee;
432
+ const e2eeOptions = options.encryption ? { ...defaultE2EEOptions, ...options.encryption } : { ...defaultE2EEOptions, ...options.e2ee };
345
433
  const req = new ConnectRequest({
346
434
  url,
347
435
  token,
@@ -361,10 +449,13 @@ class Room extends EventEmitter {
361
449
  switch (cb.message.case) {
362
450
  case "result":
363
451
  this.ffiHandle = new FfiHandle(cb.message.value.room.handle.id);
364
- this.e2eeManager = options.e2ee && new E2EEManager(this.ffiHandle.handle, e2eeOptions);
452
+ this.e2eeManager = e2eeEnabled && new E2EEManager(this.ffiHandle.handle, e2eeOptions);
365
453
  this.info = cb.message.value.room.info;
366
454
  this.connectionState = ConnectionState.CONN_CONNECTED;
367
- this.localParticipant = new LocalParticipant(cb.message.value.localParticipant);
455
+ this.localParticipant = new LocalParticipant(
456
+ cb.message.value.localParticipant,
457
+ this.roomEventLock
458
+ );
368
459
  for (const pt of cb.message.value.participants) {
369
460
  const rp = this.createRemoteParticipant(pt.participant);
370
461
  for (const pub of pt.publications) {
@@ -387,7 +478,7 @@ class Room extends EventEmitter {
387
478
  if (!this.isConnected) {
388
479
  return;
389
480
  }
390
- FfiClient.instance.request({
481
+ const res = FfiClient.instance.request({
391
482
  message: {
392
483
  case: "disconnect",
393
484
  value: {
@@ -395,6 +486,9 @@ class Room extends EventEmitter {
395
486
  }
396
487
  }
397
488
  });
489
+ await FfiClient.instance.waitFor((ev) => {
490
+ return ev.message.case == "connect" && ev.message.value.asyncId == res.asyncId;
491
+ });
398
492
  FfiClient.instance.removeListener(FfiClientEvent.FfiEvent, this.onFfiEvent);
399
493
  this.removeAllListeners();
400
494
  }
@@ -599,6 +693,7 @@ var RoomEvent = /* @__PURE__ */ ((RoomEvent2) => {
599
693
  RoomEvent2["ParticipantMetadataChanged"] = "participantMetadataChanged";
600
694
  RoomEvent2["ParticipantNameChanged"] = "participantNameChanged";
601
695
  RoomEvent2["ParticipantAttributesChanged"] = "participantAttributesChanged";
696
+ RoomEvent2["ParticipantEncryptionStatusChanged"] = "participantEncryptionStatusChanged";
602
697
  RoomEvent2["ConnectionQualityChanged"] = "connectionQualityChanged";
603
698
  RoomEvent2["DataReceived"] = "dataReceived";
604
699
  RoomEvent2["ChatMessage"] = "chatMessage";