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