@livekit/rtc-node 0.13.2 → 0.13.4
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/dist/data_streams/index.cjs +25 -0
- package/dist/data_streams/index.cjs.map +1 -0
- package/dist/data_streams/index.d.cts +11 -0
- package/dist/data_streams/index.d.ts +11 -0
- package/dist/data_streams/index.d.ts.map +1 -0
- package/dist/data_streams/index.js +3 -0
- package/dist/data_streams/index.js.map +1 -0
- package/dist/data_streams/stream_reader.cjs +145 -0
- package/dist/data_streams/stream_reader.cjs.map +1 -0
- package/dist/data_streams/stream_reader.d.cts +10 -0
- package/dist/data_streams/stream_reader.d.ts +10 -0
- package/dist/data_streams/stream_reader.d.ts.map +1 -0
- package/dist/data_streams/stream_reader.js +120 -0
- package/dist/data_streams/stream_reader.js.map +1 -0
- package/dist/data_streams/stream_writer.cjs +51 -0
- package/dist/data_streams/stream_writer.cjs.map +1 -0
- package/dist/data_streams/stream_writer.d.cts +26 -0
- package/dist/data_streams/stream_writer.d.ts +26 -0
- package/dist/data_streams/stream_writer.d.ts.map +1 -0
- package/dist/data_streams/stream_writer.js +26 -0
- package/dist/data_streams/stream_writer.js.map +1 -0
- package/dist/data_streams/types.cjs +17 -0
- package/dist/data_streams/types.cjs.map +1 -0
- package/dist/data_streams/types.d.cts +10 -0
- package/dist/data_streams/types.d.ts +10 -0
- package/dist/data_streams/types.d.ts.map +1 -0
- package/dist/data_streams/types.js +1 -0
- package/dist/data_streams/types.js.map +1 -0
- package/dist/index.cjs +7 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/log.cjs +42 -0
- package/dist/log.cjs.map +1 -0
- package/dist/log.d.cts +7 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +18 -0
- package/dist/log.js.map +1 -0
- package/dist/napi/native.d.cjs.map +1 -1
- package/dist/napi/native.d.ts +5 -5
- package/dist/native.d.ts +5 -5
- package/dist/participant.cjs +260 -16
- package/dist/participant.cjs.map +1 -1
- package/dist/participant.d.cts +40 -6
- package/dist/participant.d.ts +40 -6
- package/dist/participant.d.ts.map +1 -1
- package/dist/participant.js +263 -5
- package/dist/participant.js.map +1 -1
- package/dist/proto/ffi_pb.cjs +14 -3
- package/dist/proto/ffi_pb.cjs.map +1 -1
- package/dist/proto/ffi_pb.d.cts +81 -7
- package/dist/proto/ffi_pb.d.ts +81 -7
- package/dist/proto/ffi_pb.d.ts.map +1 -1
- package/dist/proto/ffi_pb.js +15 -4
- package/dist/proto/ffi_pb.js.map +1 -1
- package/dist/proto/room_pb.cjs +488 -30
- package/dist/proto/room_pb.cjs.map +1 -1
- package/dist/proto/room_pb.d.cts +412 -50
- package/dist/proto/room_pb.d.ts +412 -50
- package/dist/proto/room_pb.d.ts.map +1 -1
- package/dist/proto/room_pb.js +471 -29
- package/dist/proto/room_pb.js.map +1 -1
- package/dist/proto/video_frame_pb.cjs.map +1 -1
- package/dist/proto/video_frame_pb.d.cts +3 -0
- package/dist/proto/video_frame_pb.d.ts +3 -0
- package/dist/proto/video_frame_pb.d.ts.map +1 -1
- package/dist/proto/video_frame_pb.js.map +1 -1
- package/dist/room.cjs +202 -45
- package/dist/room.cjs.map +1 -1
- package/dist/room.d.cts +21 -3
- package/dist/room.d.ts +21 -3
- package/dist/room.d.ts.map +1 -1
- package/dist/room.js +203 -45
- package/dist/room.js.map +1 -1
- package/dist/types-BWsKf9LP.d.cts +93 -0
- package/dist/types-Ca3IVRvo.d.ts +93 -0
- package/dist/utils.cjs +51 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +7 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +25 -0
- package/dist/utils.js.map +1 -0
- 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/dist/video_frame.cjs +2 -0
- package/dist/video_frame.cjs.map +1 -1
- package/dist/video_frame.d.ts.map +1 -1
- package/dist/video_frame.js +2 -0
- package/dist/video_frame.js.map +1 -1
- package/package.json +9 -7
- package/src/data_streams/index.ts +7 -0
- package/src/data_streams/stream_reader.ts +166 -0
- package/src/data_streams/stream_writer.ts +36 -0
- package/src/data_streams/types.ts +61 -0
- package/src/index.ts +1 -0
- package/src/log.ts +25 -0
- package/src/napi/native.d.ts +5 -5
- package/src/participant.ts +351 -29
- package/src/proto/ffi_pb.ts +86 -1
- package/src/proto/room_pb.ts +788 -68
- package/src/proto/video_frame_pb.ts +3 -0
- package/src/room.ts +251 -68
- package/src/utils.ts +33 -0
- package/src/version.ts +1 -1
- package/src/video_frame.ts +2 -0
|
@@ -87,6 +87,9 @@ proto2.util.setEnumType(VideoRotation, "livekit.proto.VideoRotation", [
|
|
|
87
87
|
]);
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
+
* Values of this enum must not be changed
|
|
91
|
+
* It is used to serialize a rtc.VideoFrame on Python
|
|
92
|
+
*
|
|
90
93
|
* @generated from enum livekit.proto.VideoBufferType
|
|
91
94
|
*/
|
|
92
95
|
export enum VideoBufferType {
|
package/src/room.ts
CHANGED
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
|
|
5
5
|
import EventEmitter from 'events';
|
|
6
|
+
import { ReadableStream } from 'node:stream/web';
|
|
7
|
+
import { ByteStreamReader, TextStreamReader } from './data_streams/stream_reader.js';
|
|
8
|
+
import type {
|
|
9
|
+
ByteStreamHandler,
|
|
10
|
+
ByteStreamInfo,
|
|
11
|
+
StreamController,
|
|
12
|
+
TextStreamHandler,
|
|
13
|
+
TextStreamInfo,
|
|
14
|
+
} from './data_streams/types.js';
|
|
6
15
|
import type { E2EEOptions } from './e2ee.js';
|
|
7
16
|
import { E2EEManager, defaultE2EEOptions } from './e2ee.js';
|
|
8
17
|
import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
|
|
18
|
+
import { log } from './log.js';
|
|
9
19
|
import type { Participant } from './participant.js';
|
|
10
20
|
import { LocalParticipant, RemoteParticipant } from './participant.js';
|
|
11
21
|
import { EncryptionState } from './proto/e2ee_pb.js';
|
|
@@ -16,6 +26,9 @@ import {
|
|
|
16
26
|
type ConnectResponse,
|
|
17
27
|
type ConnectionQuality,
|
|
18
28
|
type DataPacketKind,
|
|
29
|
+
type DataStream_Chunk,
|
|
30
|
+
type DataStream_Header,
|
|
31
|
+
DataStream_Trailer,
|
|
19
32
|
type DisconnectResponse,
|
|
20
33
|
RoomOptions as FfiRoomOptions,
|
|
21
34
|
type IceServer,
|
|
@@ -33,6 +46,7 @@ import { RemoteAudioTrack, RemoteVideoTrack } from './track.js';
|
|
|
33
46
|
import type { LocalTrackPublication, TrackPublication } from './track_publication.js';
|
|
34
47
|
import { RemoteTrackPublication } from './track_publication.js';
|
|
35
48
|
import type { ChatMessage } from './types.js';
|
|
49
|
+
import { bigIntToNumber } from './utils.js';
|
|
36
50
|
|
|
37
51
|
export interface RtcConfiguration {
|
|
38
52
|
iceTransportType: IceTransportType;
|
|
@@ -66,6 +80,11 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
|
|
|
66
80
|
private info?: RoomInfo;
|
|
67
81
|
private ffiHandle?: FfiHandle;
|
|
68
82
|
|
|
83
|
+
private byteStreamControllers = new Map<string, StreamController<DataStream_Chunk>>();
|
|
84
|
+
private textStreamControllers = new Map<string, StreamController<DataStream_Chunk>>();
|
|
85
|
+
private byteStreamHandlers = new Map<string, ByteStreamHandler>();
|
|
86
|
+
private textStreamHandlers = new Map<string, TextStreamHandler>();
|
|
87
|
+
|
|
69
88
|
e2eeManager?: E2EEManager;
|
|
70
89
|
connectionState: ConnectionState = ConnectionState.CONN_DISCONNECTED;
|
|
71
90
|
|
|
@@ -88,8 +107,26 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
|
|
|
88
107
|
return this.ffiHandle != undefined && this.connectionState != ConnectionState.CONN_DISCONNECTED;
|
|
89
108
|
}
|
|
90
109
|
|
|
91
|
-
async getSid(): Promise<string
|
|
92
|
-
|
|
110
|
+
async getSid(): Promise<string> {
|
|
111
|
+
if (!this.isConnected) {
|
|
112
|
+
return '';
|
|
113
|
+
}
|
|
114
|
+
if (this.info?.sid && this.info.sid !== '') {
|
|
115
|
+
return this.info.sid;
|
|
116
|
+
}
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const handleRoomUpdate = (sid: string) => {
|
|
119
|
+
if (sid !== '') {
|
|
120
|
+
this.off(RoomEvent.RoomSidChanged, handleRoomUpdate);
|
|
121
|
+
resolve(sid);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
this.on(RoomEvent.RoomSidChanged, handleRoomUpdate);
|
|
125
|
+
this.once(RoomEvent.Disconnected, () => {
|
|
126
|
+
this.off(RoomEvent.RoomSidChanged, handleRoomUpdate);
|
|
127
|
+
reject('Room disconnected before room server id was available');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
93
130
|
}
|
|
94
131
|
|
|
95
132
|
async connect(url: string, token: string, opts?: RoomOptions) {
|
|
@@ -157,10 +194,50 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
|
|
|
157
194
|
this.removeAllListeners();
|
|
158
195
|
}
|
|
159
196
|
|
|
197
|
+
registerTextStreamHandler(topic: string, callback: TextStreamHandler) {
|
|
198
|
+
if (this.textStreamHandlers.has(topic)) {
|
|
199
|
+
throw new Error(`A text stream handler for topic "${topic}" has already been set.`);
|
|
200
|
+
}
|
|
201
|
+
this.textStreamHandlers.set(topic, callback);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
unregisterTextStreamHandler(topic: string) {
|
|
205
|
+
this.textStreamHandlers.delete(topic);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
registerByteStreamHandler(topic: string, callback: ByteStreamHandler) {
|
|
209
|
+
if (this.byteStreamHandlers.has(topic)) {
|
|
210
|
+
throw new Error(`A byte stream handler for topic "${topic}" has already been set.`);
|
|
211
|
+
}
|
|
212
|
+
this.byteStreamHandlers.set(topic, callback);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
unregisterByteStreamHandler(topic: string) {
|
|
216
|
+
this.byteStreamHandlers.delete(topic);
|
|
217
|
+
}
|
|
218
|
+
|
|
160
219
|
private onFfiEvent = (ffiEvent: FfiEvent) => {
|
|
161
|
-
if (
|
|
220
|
+
if (!this.localParticipant || !this.ffiHandle || !this.info) {
|
|
221
|
+
throw TypeError('cannot handle ffi events before connectCallback');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (ffiEvent.message.case == 'rpcMethodInvocation') {
|
|
225
|
+
if (
|
|
226
|
+
ffiEvent.message.value.localParticipantHandle == this.localParticipant.ffi_handle.handle
|
|
227
|
+
) {
|
|
228
|
+
this.localParticipant.handleRpcMethodInvocation(
|
|
229
|
+
ffiEvent.message.value.invocationId!,
|
|
230
|
+
ffiEvent.message.value.method!,
|
|
231
|
+
ffiEvent.message.value.requestId!,
|
|
232
|
+
ffiEvent.message.value.callerIdentity!,
|
|
233
|
+
ffiEvent.message.value.payload!,
|
|
234
|
+
ffiEvent.message.value.responseTimeoutMs!,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
} else if (
|
|
162
239
|
ffiEvent.message.case != 'roomEvent' ||
|
|
163
|
-
ffiEvent.message.value.roomHandle != this.ffiHandle
|
|
240
|
+
ffiEvent.message.value.roomHandle != this.ffiHandle.handle
|
|
164
241
|
) {
|
|
165
242
|
return;
|
|
166
243
|
}
|
|
@@ -191,96 +268,97 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
|
|
|
191
268
|
participant!.trackPublications.set(publication.sid!, publication);
|
|
192
269
|
this.emit(RoomEvent.TrackPublished, publication, participant!);
|
|
193
270
|
} else if (ev.case == 'trackUnpublished') {
|
|
194
|
-
const participant = this.
|
|
195
|
-
const publication = participant
|
|
196
|
-
participant
|
|
197
|
-
|
|
271
|
+
const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
|
|
272
|
+
const publication = participant.trackPublications.get(ev.value.publicationSid!);
|
|
273
|
+
participant.trackPublications.delete(ev.value.publicationSid!);
|
|
274
|
+
if (publication) {
|
|
275
|
+
this.emit(RoomEvent.TrackUnpublished, publication, participant);
|
|
276
|
+
}
|
|
198
277
|
} else if (ev.case == 'trackSubscribed') {
|
|
199
|
-
const ownedTrack = ev.value.track
|
|
200
|
-
const
|
|
201
|
-
const publication =
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
278
|
+
const ownedTrack = ev.value.track!;
|
|
279
|
+
const trackInfo = ownedTrack.info!;
|
|
280
|
+
const { participant, publication } = this.requirePublicationOfRemoteParticipant(
|
|
281
|
+
ev.value.participantIdentity!,
|
|
282
|
+
trackInfo.sid!,
|
|
283
|
+
);
|
|
284
|
+
publication.subscribed = true;
|
|
285
|
+
if (trackInfo.kind == TrackKind.KIND_VIDEO) {
|
|
286
|
+
publication.track = new RemoteVideoTrack(ownedTrack);
|
|
287
|
+
} else if (trackInfo.kind == TrackKind.KIND_AUDIO) {
|
|
288
|
+
publication.track = new RemoteAudioTrack(ownedTrack);
|
|
207
289
|
}
|
|
208
290
|
|
|
209
|
-
this.emit(RoomEvent.TrackSubscribed, publication
|
|
291
|
+
this.emit(RoomEvent.TrackSubscribed, publication.track!, publication, participant);
|
|
210
292
|
} else if (ev.case == 'trackUnsubscribed') {
|
|
211
|
-
const participant = this.
|
|
212
|
-
|
|
213
|
-
publication!.track = undefined;
|
|
214
|
-
publication!.subscribed = false;
|
|
215
|
-
this.emit(RoomEvent.TrackUnsubscribed, publication!.track!, publication!, participant!);
|
|
216
|
-
} else if (ev.case == 'trackSubscriptionFailed') {
|
|
217
|
-
const participant = this.remoteParticipants.get(ev.value.participantIdentity!);
|
|
218
|
-
this.emit(
|
|
219
|
-
RoomEvent.TrackSubscriptionFailed,
|
|
293
|
+
const { participant, publication } = this.requirePublicationOfRemoteParticipant(
|
|
294
|
+
ev.value.participantIdentity!,
|
|
220
295
|
ev.value.trackSid!,
|
|
221
|
-
participant!,
|
|
222
|
-
ev.value.error,
|
|
223
296
|
);
|
|
297
|
+
const track = publication.track!;
|
|
298
|
+
publication.track = undefined;
|
|
299
|
+
publication.subscribed = false;
|
|
300
|
+
this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
|
|
301
|
+
} else if (ev.case == 'trackSubscriptionFailed') {
|
|
302
|
+
const participant = this.requireRemoteParticipant(ev.value.participantIdentity!);
|
|
303
|
+
this.emit(RoomEvent.TrackSubscriptionFailed, ev.value.trackSid!, participant, ev.value.error);
|
|
224
304
|
} else if (ev.case == 'trackMuted') {
|
|
225
|
-
const participant = this.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
305
|
+
const { participant, publication } = this.requirePublicationOfParticipant(
|
|
306
|
+
ev.value.participantIdentity!,
|
|
307
|
+
ev.value.trackSid!,
|
|
308
|
+
);
|
|
309
|
+
publication.info!.muted = true;
|
|
310
|
+
if (publication.track) {
|
|
311
|
+
publication.track.info!.muted = true;
|
|
230
312
|
}
|
|
231
|
-
this.emit(RoomEvent.TrackMuted, publication
|
|
313
|
+
this.emit(RoomEvent.TrackMuted, publication, participant);
|
|
232
314
|
} else if (ev.case == 'trackUnmuted') {
|
|
233
|
-
const participant = this.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
315
|
+
const { participant, publication } = this.requirePublicationOfParticipant(
|
|
316
|
+
ev.value.participantIdentity!,
|
|
317
|
+
ev.value.trackSid!,
|
|
318
|
+
);
|
|
319
|
+
publication.info!.muted = false;
|
|
320
|
+
if (publication.track) {
|
|
321
|
+
publication.track.info!.muted = false;
|
|
238
322
|
}
|
|
239
|
-
this.emit(RoomEvent.TrackUnmuted, publication
|
|
323
|
+
this.emit(RoomEvent.TrackUnmuted, publication, participant);
|
|
240
324
|
} else if (ev.case == 'activeSpeakersChanged') {
|
|
241
325
|
const activeSpeakers = ev.value.participantIdentities.map((identity) =>
|
|
242
|
-
this.
|
|
243
|
-
);
|
|
244
|
-
this.emit(
|
|
245
|
-
RoomEvent.ActiveSpeakersChanged,
|
|
246
|
-
activeSpeakers.map((s) => s!),
|
|
326
|
+
this.requireParticipantByIdentity(identity),
|
|
247
327
|
);
|
|
328
|
+
this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
|
|
248
329
|
} else if (ev.case == 'roomMetadataChanged') {
|
|
249
330
|
this.info!.metadata = ev.value.metadata;
|
|
250
331
|
this.emit(RoomEvent.RoomMetadataChanged, this.info!.metadata!);
|
|
251
332
|
} else if (ev.case == 'participantMetadataChanged') {
|
|
252
|
-
const participant = this.
|
|
253
|
-
participant
|
|
254
|
-
this.emit(RoomEvent.ParticipantMetadataChanged, participant
|
|
333
|
+
const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
|
|
334
|
+
participant.info.metadata = ev.value.metadata;
|
|
335
|
+
this.emit(RoomEvent.ParticipantMetadataChanged, participant.metadata, participant);
|
|
255
336
|
} else if (ev.case == 'participantNameChanged') {
|
|
256
|
-
const participant = this.
|
|
257
|
-
participant
|
|
258
|
-
this.emit(RoomEvent.ParticipantNameChanged, participant
|
|
337
|
+
const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
|
|
338
|
+
participant.info.name = ev.value.name;
|
|
339
|
+
this.emit(RoomEvent.ParticipantNameChanged, participant.name!, participant);
|
|
259
340
|
} else if (ev.case == 'participantAttributesChanged') {
|
|
260
|
-
const participant = this.
|
|
261
|
-
participant
|
|
262
|
-
(
|
|
263
|
-
|
|
264
|
-
return
|
|
341
|
+
const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
|
|
342
|
+
participant.info.attributes = ev.value.attributes.reduce(
|
|
343
|
+
(acc, value) => {
|
|
344
|
+
acc[value.key!] = value.value!;
|
|
345
|
+
return acc;
|
|
265
346
|
},
|
|
266
347
|
{} as Record<string, string>,
|
|
267
348
|
);
|
|
268
349
|
if (Object.keys(ev.value.changedAttributes).length > 0) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
},
|
|
276
|
-
{} as Record<string, string>,
|
|
277
|
-
),
|
|
278
|
-
participant!,
|
|
350
|
+
const changedAttributes = ev.value.changedAttributes.reduce(
|
|
351
|
+
(acc, value) => {
|
|
352
|
+
acc[value.key!] = value.value!;
|
|
353
|
+
return acc;
|
|
354
|
+
},
|
|
355
|
+
{} as Record<string, string>,
|
|
279
356
|
);
|
|
357
|
+
this.emit(RoomEvent.ParticipantAttributesChanged, changedAttributes, participant);
|
|
280
358
|
}
|
|
281
359
|
} else if (ev.case == 'connectionQualityChanged') {
|
|
282
|
-
const participant = this.
|
|
283
|
-
this.emit(RoomEvent.ConnectionQualityChanged, ev.value.quality!, participant
|
|
360
|
+
const participant = this.requireParticipantByIdentity(ev.value.participantIdentity!);
|
|
361
|
+
this.emit(RoomEvent.ConnectionQualityChanged, ev.value.quality!, participant);
|
|
284
362
|
} else if (ev.case == 'chatMessage') {
|
|
285
363
|
const participant = this.retrieveParticipantByIdentity(ev.value.participantIdentity!);
|
|
286
364
|
const { id, message: messageText, timestamp, editTimestamp, generated } = ev.value.message!;
|
|
@@ -334,6 +412,14 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
|
|
|
334
412
|
this.emit(RoomEvent.Reconnecting);
|
|
335
413
|
} else if (ev.case == 'reconnected') {
|
|
336
414
|
this.emit(RoomEvent.Reconnected);
|
|
415
|
+
} else if (ev.case == 'roomSidChanged') {
|
|
416
|
+
this.emit(RoomEvent.RoomSidChanged, ev.value.sid!);
|
|
417
|
+
} else if (ev.case === 'streamHeaderReceived' && ev.value.header) {
|
|
418
|
+
this.handleStreamHeader(ev.value.header, ev.value.participantIdentity!);
|
|
419
|
+
} else if (ev.case === 'streamChunkReceived' && ev.value.chunk) {
|
|
420
|
+
this.handleStreamChunk(ev.value.chunk);
|
|
421
|
+
} else if (ev.case === 'streamTrailerReceived' && ev.value.trailer) {
|
|
422
|
+
this.handleStreamTrailer(ev.value.trailer);
|
|
337
423
|
}
|
|
338
424
|
};
|
|
339
425
|
|
|
@@ -390,6 +476,100 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
|
|
|
390
476
|
this.remoteParticipants.set(ownedInfo.info!.identity!, participant);
|
|
391
477
|
return participant;
|
|
392
478
|
}
|
|
479
|
+
|
|
480
|
+
private handleStreamHeader(streamHeader: DataStream_Header, participantIdentity: string) {
|
|
481
|
+
if (streamHeader.contentHeader.case === 'byteHeader') {
|
|
482
|
+
const streamHandlerCallback = this.byteStreamHandlers.get(streamHeader.topic ?? '');
|
|
483
|
+
|
|
484
|
+
if (!streamHandlerCallback) {
|
|
485
|
+
log.debug('ignoring incoming byte stream due to no handler for topic', streamHeader.topic);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
let streamController: ReadableStreamDefaultController<DataStream_Chunk>;
|
|
489
|
+
const stream = new ReadableStream({
|
|
490
|
+
start: (controller) => {
|
|
491
|
+
streamController = controller;
|
|
492
|
+
this.byteStreamControllers.set(streamHeader.streamId!, {
|
|
493
|
+
header: streamHeader,
|
|
494
|
+
controller: streamController,
|
|
495
|
+
startTime: Date.now(),
|
|
496
|
+
});
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
const info: ByteStreamInfo = {
|
|
500
|
+
streamId: streamHeader.streamId!,
|
|
501
|
+
name: streamHeader.contentHeader.value.name ?? 'unknown',
|
|
502
|
+
mimeType: streamHeader.mimeType!,
|
|
503
|
+
totalSize: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
|
504
|
+
topic: streamHeader.topic!,
|
|
505
|
+
timestamp: bigIntToNumber(streamHeader.timestamp!),
|
|
506
|
+
attributes: streamHeader.attributes,
|
|
507
|
+
};
|
|
508
|
+
streamHandlerCallback(
|
|
509
|
+
new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)),
|
|
510
|
+
{ identity: participantIdentity },
|
|
511
|
+
);
|
|
512
|
+
} else if (streamHeader.contentHeader.case === 'textHeader') {
|
|
513
|
+
const streamHandlerCallback = this.textStreamHandlers.get(streamHeader.topic ?? '');
|
|
514
|
+
|
|
515
|
+
if (!streamHandlerCallback) {
|
|
516
|
+
log.debug('ignoring incoming text stream due to no handler for topic', streamHeader.topic);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
let streamController: ReadableStreamDefaultController<DataStream_Chunk>;
|
|
520
|
+
const stream = new ReadableStream<DataStream_Chunk>({
|
|
521
|
+
start: (controller) => {
|
|
522
|
+
streamController = controller;
|
|
523
|
+
this.textStreamControllers.set(streamHeader.streamId!, {
|
|
524
|
+
header: streamHeader,
|
|
525
|
+
controller: streamController,
|
|
526
|
+
startTime: Date.now(),
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
});
|
|
530
|
+
const info: TextStreamInfo = {
|
|
531
|
+
streamId: streamHeader.streamId!,
|
|
532
|
+
mimeType: streamHeader.mimeType!,
|
|
533
|
+
totalSize: streamHeader.totalLength ? Number(streamHeader.totalLength) : undefined,
|
|
534
|
+
topic: streamHeader.topic!,
|
|
535
|
+
timestamp: Number(streamHeader.timestamp),
|
|
536
|
+
attributes: streamHeader.attributes,
|
|
537
|
+
};
|
|
538
|
+
streamHandlerCallback(
|
|
539
|
+
new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)),
|
|
540
|
+
{ identity: participantIdentity },
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
private handleStreamChunk(chunk: DataStream_Chunk) {
|
|
546
|
+
const fileBuffer = this.byteStreamControllers.get(chunk.streamId!);
|
|
547
|
+
if (fileBuffer) {
|
|
548
|
+
if (chunk.content!.length > 0) {
|
|
549
|
+
fileBuffer.controller.enqueue(chunk);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
const textBuffer = this.textStreamControllers.get(chunk.streamId!);
|
|
553
|
+
if (textBuffer) {
|
|
554
|
+
if (chunk.content!.length > 0) {
|
|
555
|
+
textBuffer.controller.enqueue(chunk);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
private handleStreamTrailer(trailer: DataStream_Trailer) {
|
|
561
|
+
const streamId = trailer.streamId!;
|
|
562
|
+
const fileBuffer = this.byteStreamControllers.get(streamId);
|
|
563
|
+
if (fileBuffer) {
|
|
564
|
+
fileBuffer.controller.close();
|
|
565
|
+
this.byteStreamControllers.delete(streamId);
|
|
566
|
+
}
|
|
567
|
+
const textBuffer = this.textStreamControllers.get(streamId);
|
|
568
|
+
if (textBuffer) {
|
|
569
|
+
textBuffer.controller.close();
|
|
570
|
+
this.byteStreamControllers.delete(streamId);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
393
573
|
}
|
|
394
574
|
|
|
395
575
|
export class ConnectError extends Error {
|
|
@@ -428,6 +608,7 @@ export type RoomCallbacks = {
|
|
|
428
608
|
trackUnmuted: (publication: TrackPublication, participant: Participant) => void;
|
|
429
609
|
activeSpeakersChanged: (speakers: Participant[]) => void;
|
|
430
610
|
roomMetadataChanged: (metadata: string) => void;
|
|
611
|
+
roomInfoUpdated: (info: RoomInfo) => void;
|
|
431
612
|
participantMetadataChanged: (metadata: string | undefined, participant: Participant) => void;
|
|
432
613
|
participantNameChanged: (name: string, participant: Participant) => void;
|
|
433
614
|
participantAttributesChanged: (
|
|
@@ -449,6 +630,7 @@ export type RoomCallbacks = {
|
|
|
449
630
|
disconnected: (reason: DisconnectReason) => void;
|
|
450
631
|
reconnecting: () => void;
|
|
451
632
|
reconnected: () => void;
|
|
633
|
+
roomSidChanged: (sid: string) => void;
|
|
452
634
|
};
|
|
453
635
|
|
|
454
636
|
export enum RoomEvent {
|
|
@@ -466,6 +648,7 @@ export enum RoomEvent {
|
|
|
466
648
|
TrackUnmuted = 'trackUnmuted',
|
|
467
649
|
ActiveSpeakersChanged = 'activeSpeakersChanged',
|
|
468
650
|
RoomMetadataChanged = 'roomMetadataChanged',
|
|
651
|
+
RoomSidChanged = 'roomSidChanged',
|
|
469
652
|
ParticipantMetadataChanged = 'participantMetadataChanged',
|
|
470
653
|
ParticipantNameChanged = 'participantNameChanged',
|
|
471
654
|
ParticipantAttributesChanged = 'participantAttributesChanged',
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
/** convert bigints to numbers preserving undefined values */
|
|
6
|
+
export function bigIntToNumber<T extends bigint | undefined>(
|
|
7
|
+
value: T,
|
|
8
|
+
): T extends bigint ? number : undefined {
|
|
9
|
+
return (value !== undefined ? Number(value) : undefined) as T extends bigint ? number : undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** convert numbers to bigints preserving undefined values */
|
|
13
|
+
export function numberToBigInt<T extends number | undefined>(
|
|
14
|
+
value: T,
|
|
15
|
+
): T extends number ? bigint : undefined {
|
|
16
|
+
return (value !== undefined ? BigInt(value) : undefined) as T extends number ? bigint : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function splitUtf8(s: string, n: number): string[] {
|
|
20
|
+
// adapted from https://stackoverflow.com/a/6043797
|
|
21
|
+
const result: string[] = [];
|
|
22
|
+
while (s.length > n) {
|
|
23
|
+
let k = n;
|
|
24
|
+
// Move back to find the start of a UTF-8 character
|
|
25
|
+
while ((s.charCodeAt(k) & 0xc0) === 0x80) {
|
|
26
|
+
k--;
|
|
27
|
+
}
|
|
28
|
+
result.push(s.slice(0, k));
|
|
29
|
+
s = s.slice(k);
|
|
30
|
+
}
|
|
31
|
+
result.push(s);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.13.
|
|
1
|
+
export const SDK_VERSION = "0.13.4";
|
package/src/video_frame.ts
CHANGED