@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/dist/room.js CHANGED
@@ -5,7 +5,7 @@ import { E2EEManager, defaultE2EEOptions } from "./e2ee.js";
5
5
  import { FfiClient, FfiClientEvent, FfiHandle } from "./ffi_client.js";
6
6
  import { log } from "./log.js";
7
7
  import { LocalParticipant, RemoteParticipant } from "./participant.js";
8
- import { EncryptionState, EncryptionType } from "./proto/e2ee_pb.js";
8
+ import { EncryptionState } from "./proto/e2ee_pb.js";
9
9
  import {
10
10
  ConnectRequest,
11
11
  ConnectionState,
@@ -39,7 +39,7 @@ class Room extends EventEmitter {
39
39
  * the local participant to acquire the lock while doing state updates related to FFI events
40
40
  * before processing the next events
41
41
  */
42
- this.roomEventLock = new Mutex();
42
+ this.ffiEventLock = new Mutex();
43
43
  this.byteStreamControllers = /* @__PURE__ */ new Map();
44
44
  this.textStreamControllers = /* @__PURE__ */ new Map();
45
45
  this.byteStreamHandlers = /* @__PURE__ */ new Map();
@@ -48,304 +48,302 @@ class Room extends EventEmitter {
48
48
  this.connectionState = ConnectionState.CONN_DISCONNECTED;
49
49
  this.remoteParticipants = /* @__PURE__ */ new Map();
50
50
  this.onFfiEvent = async (ffiEvent) => {
51
- if (!this.localParticipant || !this.ffiHandle || !this.info) {
52
- this.preConnectEvents.push(ffiEvent);
53
- return;
54
- }
55
- for (const ev of this.preConnectEvents) {
56
- await this.processFfiEvent(ev);
51
+ const unlock = await this.ffiEventLock.lock();
52
+ try {
53
+ if (!this.localParticipant || !this.ffiHandle || !this.info) {
54
+ this.preConnectEvents.push(ffiEvent);
55
+ return;
56
+ }
57
+ for (const ev of this.preConnectEvents) {
58
+ await this.processFfiEvent(ev);
59
+ }
60
+ this.preConnectEvents = [];
61
+ await this.processFfiEvent(ffiEvent);
62
+ } finally {
63
+ unlock();
57
64
  }
58
- this.preConnectEvents = [];
59
- await this.processFfiEvent(ffiEvent);
60
65
  };
61
66
  this.processFfiEvent = async (ffiEvent) => {
62
67
  if (!this.localParticipant || !this.ffiHandle || !this.info) {
63
68
  throw new Error("processFfiEvent called before connect");
64
69
  }
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;
70
+ if (ffiEvent.message.case == "rpcMethodInvocation") {
71
+ if (ffiEvent.message.value.localParticipantHandle == this.localParticipant.ffi_handle.handle) {
72
+ this.localParticipant.handleRpcMethodInvocation(
73
+ ffiEvent.message.value.invocationId,
74
+ ffiEvent.message.value.method,
75
+ ffiEvent.message.value.requestId,
76
+ ffiEvent.message.value.callerIdentity,
77
+ ffiEvent.message.value.payload,
78
+ ffiEvent.message.value.responseTimeoutMs
79
+ );
81
80
  }
82
- const ev = ffiEvent.message.value.message;
83
- if (process.env.LIVEKIT_DEBUG_LOG_ROOM_EVENTS) {
84
- console.log("Room event:", ev);
81
+ return;
82
+ } else if (ffiEvent.message.case != "roomEvent" || ffiEvent.message.value.roomHandle != this.ffiHandle.handle) {
83
+ return;
84
+ }
85
+ const ev = ffiEvent.message.value.message;
86
+ if (process.env.LIVEKIT_DEBUG_LOG_ROOM_EVENTS) {
87
+ console.log("Room event:", ev);
88
+ }
89
+ if (ev.case == "participantConnected") {
90
+ const participant = this.createRemoteParticipant(ev.value.info);
91
+ this.remoteParticipants.set(participant.identity, participant);
92
+ this.emit("participantConnected" /* ParticipantConnected */, participant);
93
+ } else if (ev.case == "participantDisconnected") {
94
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity);
95
+ if (participant) {
96
+ this.remoteParticipants.delete(participant.identity);
97
+ participant.info.disconnectReason = ev.value.disconnectReason;
98
+ this.emit("participantDisconnected" /* ParticipantDisconnected */, participant);
99
+ } else {
100
+ console.log(`RoomEvent.ParticipantDisconnected: Could not find participant`);
85
101
  }
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
- );
102
+ } else if (ev.case == "localTrackPublished") {
103
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid);
104
+ this.emit("localTrackPublished" /* LocalTrackPublished */, publication, this.localParticipant);
105
+ } else if (ev.case == "localTrackUnpublished") {
106
+ const publication = this.localParticipant.trackPublications.get(ev.value.publicationSid);
107
+ this.localParticipant.trackPublications.delete(ev.value.publicationSid);
108
+ this.emit("localTrackUnpublished" /* LocalTrackUnpublished */, publication, this.localParticipant);
109
+ } else if (ev.case == "localTrackSubscribed") {
110
+ const publication = this.localParticipant.trackPublications.get(ev.value.trackSid);
111
+ if (publication) {
112
+ publication.resolveFirstSubscription();
113
+ this.emit("localTrackSubscribed" /* LocalTrackSubscribed */, publication.track);
114
+ } else {
115
+ console.warn(`RoomEvent.LocalTrackSubscribed: Publication not found: ${ev.value.trackSid}`);
116
+ }
117
+ } else if (ev.case == "trackPublished") {
118
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity);
119
+ const publication = new RemoteTrackPublication(ev.value.publication);
120
+ if (participant) {
121
+ participant.trackPublications.set(publication.sid, publication);
122
+ } else {
123
+ console.warn(
124
+ `RoomEvent.TrackPublished: Could not find participant: ${ev.value.participantIdentity}`
125
+ );
126
+ }
127
+ this.emit("trackPublished" /* TrackPublished */, publication, participant);
128
+ } else if (ev.case == "trackUnpublished") {
129
+ const participant = this.requireRemoteParticipant(ev.value.participantIdentity);
130
+ const publication = participant.trackPublications.get(ev.value.publicationSid);
131
+ participant.trackPublications.delete(ev.value.publicationSid);
132
+ if (publication) {
133
+ this.emit("trackUnpublished" /* TrackUnpublished */, publication, participant);
134
+ } else {
135
+ console.warn(`RoomEvent.TrackUnpublished: Could not find publication`);
136
+ }
137
+ } else if (ev.case == "trackSubscribed") {
138
+ const ownedTrack = ev.value.track;
139
+ const trackInfo = ownedTrack.info;
140
+ try {
141
+ const { participant, publication } = this.requirePublicationOfRemoteParticipant(
142
+ ev.value.participantIdentity,
143
+ trackInfo.sid
144
+ );
145
+ publication.subscribed = true;
146
+ if (trackInfo.kind == TrackKind.KIND_VIDEO) {
147
+ publication.track = new RemoteVideoTrack(ownedTrack);
148
+ } else if (trackInfo.kind == TrackKind.KIND_AUDIO) {
149
+ publication.track = new RemoteAudioTrack(ownedTrack);
125
150
  }
126
- this.emit("trackPublished" /* TrackPublished */, publication, participant);
127
- } else if (ev.case == "trackUnpublished") {
151
+ this.emit("trackSubscribed" /* TrackSubscribed */, publication.track, publication, participant);
152
+ } catch (e) {
153
+ console.warn(`RoomEvent.TrackSubscribed: ${e.message}`);
154
+ }
155
+ } else if (ev.case == "trackUnsubscribed") {
156
+ try {
157
+ const { participant, publication } = this.requirePublicationOfRemoteParticipant(
158
+ ev.value.participantIdentity,
159
+ ev.value.trackSid
160
+ );
161
+ const track = publication.track;
162
+ publication.track = void 0;
163
+ publication.subscribed = false;
164
+ this.emit("trackUnsubscribed" /* TrackUnsubscribed */, track, publication, participant);
165
+ } catch (e) {
166
+ console.warn(`RoomEvent.TrackUnsubscribed: ${e.message}`);
167
+ }
168
+ } else if (ev.case == "trackSubscriptionFailed") {
169
+ try {
128
170
  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
159
- );
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);
170
- this.emit(
171
- "trackSubscriptionFailed" /* TrackSubscriptionFailed */,
172
- ev.value.trackSid,
173
- participant,
174
- ev.value.error
175
- );
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}`);
171
+ this.emit(
172
+ "trackSubscriptionFailed" /* TrackSubscriptionFailed */,
173
+ ev.value.trackSid,
174
+ participant,
175
+ ev.value.error
176
+ );
177
+ } catch (e) {
178
+ console.warn(`RoomEvent.TrackSubscriptionFailed: ${e.message}`);
179
+ }
180
+ } else if (ev.case == "trackMuted") {
181
+ try {
182
+ const { participant, publication } = this.requirePublicationOfParticipant(
183
+ ev.value.participantIdentity,
184
+ ev.value.trackSid
185
+ );
186
+ publication.info.muted = true;
187
+ if (publication.track) {
188
+ publication.track.info.muted = true;
226
189
  }
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}`);
190
+ this.emit("trackMuted" /* TrackMuted */, publication, participant);
191
+ } catch (e) {
192
+ console.warn(`RoomEvent.TrackMuted: ${e.message}`);
193
+ }
194
+ } else if (ev.case == "trackUnmuted") {
195
+ try {
196
+ const { participant, publication } = this.requirePublicationOfParticipant(
197
+ ev.value.participantIdentity,
198
+ ev.value.trackSid
199
+ );
200
+ publication.info.muted = false;
201
+ if (publication.track) {
202
+ publication.track.info.muted = false;
234
203
  }
235
- } else if (ev.case == "participantAttributesChanged") {
236
- try {
237
- const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
238
- participant.info.attributes = ev.value.attributes.reduce(
204
+ this.emit("trackUnmuted" /* TrackUnmuted */, publication, participant);
205
+ } catch (e) {
206
+ console.warn(`RoomEvent.TrackUnmuted: ${e.message}`);
207
+ }
208
+ } else if (ev.case == "activeSpeakersChanged") {
209
+ try {
210
+ const activeSpeakers = ev.value.participantIdentities.map(
211
+ (identity) => this.requireParticipantByIdentity(identity)
212
+ );
213
+ this.emit("activeSpeakersChanged" /* ActiveSpeakersChanged */, activeSpeakers);
214
+ } catch (e) {
215
+ console.warn(`RoomEvent.ActiveSpeakersChanged: ${e.message}`);
216
+ }
217
+ } else if (ev.case == "roomMetadataChanged") {
218
+ this.info.metadata = ev.value.metadata ?? "";
219
+ this.emit("roomMetadataChanged" /* RoomMetadataChanged */, this.info.metadata);
220
+ } else if (ev.case == "participantMetadataChanged") {
221
+ try {
222
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
223
+ participant.info.metadata = ev.value.metadata;
224
+ this.emit("participantMetadataChanged" /* ParticipantMetadataChanged */, participant.metadata, participant);
225
+ } catch (e) {
226
+ console.warn(`RoomEvent.ParticipantMetadataChanged: ${e.message}`);
227
+ }
228
+ } else if (ev.case == "participantNameChanged") {
229
+ try {
230
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
231
+ participant.info.name = ev.value.name;
232
+ this.emit("participantNameChanged" /* ParticipantNameChanged */, participant.name, participant);
233
+ } catch (e) {
234
+ console.warn(`RoomEvent.ParticipantNameChanged: ${e.message}`);
235
+ }
236
+ } else if (ev.case == "participantAttributesChanged") {
237
+ try {
238
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
239
+ participant.info.attributes = ev.value.attributes.reduce(
240
+ (acc, value) => {
241
+ acc[value.key] = value.value;
242
+ return acc;
243
+ },
244
+ {}
245
+ );
246
+ if (Object.keys(ev.value.changedAttributes).length > 0) {
247
+ const changedAttributes = ev.value.changedAttributes.reduce(
239
248
  (acc, value) => {
240
249
  acc[value.key] = value.value;
241
250
  return acc;
242
251
  },
243
252
  {}
244
253
  );
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"));
254
+ this.emit("participantAttributesChanged" /* ParticipantAttributesChanged */, changedAttributes, participant);
304
255
  }
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);
256
+ } catch (e) {
257
+ console.warn(`RoomEvent.ParticipantAttributesChanged: ${e.message}`);
258
+ }
259
+ } else if (ev.case == "connectionQualityChanged") {
260
+ try {
261
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
262
+ this.emit("connectionQualityChanged" /* ConnectionQualityChanged */, ev.value.quality, participant);
263
+ } catch (e) {
264
+ console.warn(`RoomEvent.ConnectionQualityChanged: ${e.message}`);
265
+ }
266
+ } else if (ev.case == "chatMessage") {
267
+ const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity);
268
+ const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message;
269
+ const message = {
270
+ id,
271
+ message: messageText,
272
+ timestamp: Number(timestamp),
273
+ editTimestamp: Number(editTimestamp),
274
+ generated
275
+ };
276
+ this.emit("chatMessage" /* ChatMessage */, message, participant);
277
+ } else if (ev.case == "dataPacketReceived") {
278
+ const participant = this.remoteParticipants.get(ev.value.participantIdentity);
279
+ const dataPacket = ev.value.value;
280
+ switch (dataPacket.case) {
281
+ case "user":
282
+ const buffer = FfiClient.instance.copyBuffer(
283
+ dataPacket.value.data.data.dataPtr,
284
+ Number(dataPacket.value.data.data.dataLen)
285
+ );
286
+ new FfiHandle(dataPacket.value.data.handle.id).dispose();
338
287
  this.emit(
339
- "participantEncryptionStatusChanged" /* ParticipantEncryptionStatusChanged */,
340
- !!ev.value.isEncrypted,
341
- participant
288
+ "dataReceived" /* DataReceived */,
289
+ buffer,
290
+ participant,
291
+ ev.value.kind,
292
+ dataPacket.value.topic
342
293
  );
343
- } catch (e) {
344
- console.warn(`RoomEvent.ParticipantEncryptionStatusChanged: ${e.message}`);
294
+ break;
295
+ case "sipDtmf":
296
+ const { code, digit } = dataPacket.value;
297
+ this.emit("dtmfReceived" /* DtmfReceived */, code, digit, participant);
298
+ break;
299
+ default:
300
+ break;
301
+ }
302
+ } else if (ev.case == "e2eeStateChanged") {
303
+ if (ev.value.state == EncryptionState.INTERNAL_ERROR) {
304
+ this.emit("encryptionError" /* EncryptionError */, new Error("internal server error"));
305
+ }
306
+ } else if (ev.case == "connectionStateChanged") {
307
+ this.connectionState = ev.value.state;
308
+ this.emit("connectionStateChanged" /* ConnectionStateChanged */, this.connectionState);
309
+ } else if (ev.case == "disconnected") {
310
+ this.emit("disconnected" /* Disconnected */, ev.value.reason);
311
+ } else if (ev.case == "reconnecting") {
312
+ this.emit("reconnecting" /* Reconnecting */);
313
+ } else if (ev.case == "reconnected") {
314
+ this.emit("reconnected" /* Reconnected */);
315
+ } else if (ev.case == "roomSidChanged") {
316
+ this.emit("roomSidChanged" /* RoomSidChanged */, ev.value.sid);
317
+ } else if (ev.case === "streamHeaderReceived" && ev.value.header) {
318
+ this.handleStreamHeader(ev.value.header, ev.value.participantIdentity);
319
+ } else if (ev.case === "streamChunkReceived" && ev.value.chunk) {
320
+ this.handleStreamChunk(ev.value.chunk);
321
+ } else if (ev.case === "streamTrailerReceived" && ev.value.trailer) {
322
+ this.handleStreamTrailer(ev.value.trailer);
323
+ } else if (ev.case === "roomUpdated") {
324
+ this.info = ev.value;
325
+ this.emit("roomUpdated" /* RoomUpdated */);
326
+ } else if (ev.case === "moved") {
327
+ this.info = ev.value;
328
+ this.emit("moved" /* Moved */);
329
+ } else if (ev.case === "participantsUpdated") {
330
+ for (const info of ev.value.participants) {
331
+ const participant = this.retrieveParticipantByIdentity(info.identity);
332
+ if (participant) {
333
+ participant.info = info;
345
334
  }
346
335
  }
347
- } finally {
348
- unlock();
336
+ } else if (ev.case === "participantEncryptionStatusChanged") {
337
+ try {
338
+ const participant = this.requireParticipantByIdentity(ev.value.participantIdentity);
339
+ this.emit(
340
+ "participantEncryptionStatusChanged" /* ParticipantEncryptionStatusChanged */,
341
+ !!ev.value.isEncrypted,
342
+ participant
343
+ );
344
+ } catch (e) {
345
+ console.warn(`RoomEvent.ParticipantEncryptionStatusChanged: ${e.message}`);
346
+ }
349
347
  }
350
348
  };
351
349
  }
@@ -421,10 +419,10 @@ class Room extends EventEmitter {
421
419
  }
422
420
  /**
423
421
  * Connects to a LiveKit room using the provided URL and access token.
424
- * @param url The WebSocket URL of the LiveKit server
425
- * @param token A valid LiveKit access token for authentication
426
- * @param opts Optional room configuration options
427
- * @throws ConnectError if connection fails
422
+ * @param url - The WebSocket URL of the LiveKit server
423
+ * @param token - A valid LiveKit access token for authentication
424
+ * @param opts - Optional room configuration options
425
+ * @throws ConnectError - if connection fails
428
426
  */
429
427
  async connect(url, token, opts) {
430
428
  const options = { ...defaultRoomOptions, ...opts };
@@ -454,7 +452,7 @@ class Room extends EventEmitter {
454
452
  this.connectionState = ConnectionState.CONN_CONNECTED;
455
453
  this.localParticipant = new LocalParticipant(
456
454
  cb.message.value.localParticipant,
457
- this.roomEventLock
455
+ this.ffiEventLock
458
456
  );
459
457
  for (const pt of cb.message.value.participants) {
460
458
  const rp = this.createRemoteParticipant(pt.participant);
@@ -487,7 +485,7 @@ class Room extends EventEmitter {
487
485
  }
488
486
  });
489
487
  await FfiClient.instance.waitFor((ev) => {
490
- return ev.message.case == "connect" && ev.message.value.asyncId == res.asyncId;
488
+ return ev.message.case == "disconnect" && ev.message.value.asyncId == res.asyncId;
491
489
  });
492
490
  FfiClient.instance.removeListener(FfiClientEvent.FfiEvent, this.onFfiEvent);
493
491
  this.removeAllListeners();
@@ -495,9 +493,9 @@ class Room extends EventEmitter {
495
493
  /**
496
494
  * Registers a handler for incoming text data streams on a specific topic.
497
495
  * Text streams are used for receiving structured text data from other participants.
498
- * @param topic The topic to listen for text streams on
499
- * @param callback Function to handle incoming text stream data
500
- * @throws Error if a handler for this topic is already registered
496
+ * @param topic - The topic to listen for text streams on
497
+ * @param callback - Function to handle incoming text stream data
498
+ * @throws Error - if a handler for this topic is already registered
501
499
  */
502
500
  registerTextStreamHandler(topic, callback) {
503
501
  if (this.textStreamHandlers.has(topic)) {
@@ -511,9 +509,9 @@ class Room extends EventEmitter {
511
509
  /**
512
510
  * Registers a handler for incoming byte data streams on a specific topic.
513
511
  * Byte streams are used for receiving binary data like files from other participants.
514
- * @param topic The topic to listen for byte streams on
515
- * @param callback Function to handle incoming byte stream data
516
- * @throws Error if a handler for this topic is already registered
512
+ * @param topic - The topic to listen for byte streams on
513
+ * @param callback - Function to handle incoming byte stream data
514
+ * @throws Error - if a handler for this topic is already registered
517
515
  */
518
516
  registerByteStreamHandler(topic, callback) {
519
517
  if (this.byteStreamHandlers.has(topic)) {