@livekit/rtc-node 0.10.4 → 0.11.1

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 (136) hide show
  1. package/README.md +54 -2
  2. package/build.rs +1 -1
  3. package/dist/audio_frame.d.ts +1 -1
  4. package/dist/audio_frame.d.ts.map +1 -1
  5. package/dist/audio_frame.js +4 -4
  6. package/dist/audio_frame.js.map +1 -1
  7. package/dist/audio_resampler.d.ts.map +1 -1
  8. package/dist/audio_resampler.js +8 -7
  9. package/dist/audio_resampler.js.map +1 -1
  10. package/dist/audio_source.d.ts.map +1 -1
  11. package/dist/audio_source.js +8 -4
  12. package/dist/audio_source.js.map +1 -1
  13. package/dist/audio_stream.d.ts +1 -1
  14. package/dist/audio_stream.d.ts.map +1 -1
  15. package/dist/audio_stream.js +4 -3
  16. package/dist/audio_stream.js.map +1 -1
  17. package/dist/e2ee.d.ts.map +1 -1
  18. package/dist/e2ee.js +25 -25
  19. package/dist/e2ee.js.map +1 -1
  20. package/dist/ffi_client.d.ts +3 -3
  21. package/dist/ffi_client.d.ts.map +1 -1
  22. package/dist/ffi_client.js +9 -7
  23. package/dist/ffi_client.js.map +1 -1
  24. package/dist/index.d.ts +29 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +34 -4
  27. package/dist/index.js.map +1 -1
  28. package/dist/napi/native.d.ts +1 -0
  29. package/dist/participant.d.ts +48 -2
  30. package/dist/participant.d.ts.map +1 -1
  31. package/dist/participant.js +143 -24
  32. package/dist/participant.js.map +1 -1
  33. package/dist/proto/audio_frame_pb.d.ts +451 -526
  34. package/dist/proto/audio_frame_pb.d.ts.map +1 -1
  35. package/dist/proto/audio_frame_pb.js +200 -1179
  36. package/dist/proto/audio_frame_pb.js.map +1 -1
  37. package/dist/proto/e2ee_pb.d.ts +264 -333
  38. package/dist/proto/e2ee_pb.d.ts.map +1 -1
  39. package/dist/proto/e2ee_pb.js +136 -810
  40. package/dist/proto/e2ee_pb.js.map +1 -1
  41. package/dist/proto/ffi_pb.d.ts +175 -129
  42. package/dist/proto/ffi_pb.d.ts.map +1 -1
  43. package/dist/proto/ffi_pb.js +58 -395
  44. package/dist/proto/ffi_pb.js.map +1 -1
  45. package/dist/proto/handle_pb.d.ts +14 -13
  46. package/dist/proto/handle_pb.d.ts.map +1 -1
  47. package/dist/proto/handle_pb.js +8 -39
  48. package/dist/proto/handle_pb.js.map +1 -1
  49. package/dist/proto/participant_pb.d.ts +54 -52
  50. package/dist/proto/participant_pb.d.ts.map +1 -1
  51. package/dist/proto/participant_pb.js +18 -90
  52. package/dist/proto/participant_pb.js.map +1 -1
  53. package/dist/proto/room_pb.d.ts +1042 -1187
  54. package/dist/proto/room_pb.d.ts.map +1 -1
  55. package/dist/proto/room_pb.js +470 -2938
  56. package/dist/proto/room_pb.js.map +1 -1
  57. package/dist/proto/rpc_pb.d.ts +235 -0
  58. package/dist/proto/rpc_pb.d.ts.map +1 -0
  59. package/dist/proto/rpc_pb.js +74 -0
  60. package/dist/proto/rpc_pb.js.map +1 -0
  61. package/dist/proto/stats_pb.d.ts +738 -800
  62. package/dist/proto/stats_pb.d.ts.map +1 -1
  63. package/dist/proto/stats_pb.js +218 -1960
  64. package/dist/proto/stats_pb.js.map +1 -1
  65. package/dist/proto/track_pb.d.ts +225 -258
  66. package/dist/proto/track_pb.d.ts.map +1 -1
  67. package/dist/proto/track_pb.js +98 -591
  68. package/dist/proto/track_pb.js.map +1 -1
  69. package/dist/proto/video_frame_pb.d.ts +357 -390
  70. package/dist/proto/video_frame_pb.d.ts.map +1 -1
  71. package/dist/proto/video_frame_pb.js +137 -790
  72. package/dist/proto/video_frame_pb.js.map +1 -1
  73. package/dist/room.d.ts +21 -7
  74. package/dist/room.d.ts.map +1 -1
  75. package/dist/room.js +134 -54
  76. package/dist/room.js.map +1 -1
  77. package/dist/rpc.d.ts +78 -0
  78. package/dist/rpc.d.ts.map +1 -0
  79. package/dist/rpc.js +69 -0
  80. package/dist/rpc.js.map +1 -0
  81. package/dist/track.d.ts.map +1 -1
  82. package/dist/track.js +7 -3
  83. package/dist/track.js.map +1 -1
  84. package/dist/track_publication.d.ts.map +1 -1
  85. package/dist/track_publication.js +3 -2
  86. package/dist/track_publication.js.map +1 -1
  87. package/dist/version.d.ts +2 -0
  88. package/dist/version.d.ts.map +1 -0
  89. package/dist/version.js +2 -0
  90. package/dist/version.js.map +1 -0
  91. package/dist/video_frame.d.ts +2 -2
  92. package/dist/video_frame.d.ts.map +1 -1
  93. package/dist/video_frame.js +47 -25
  94. package/dist/video_frame.js.map +1 -1
  95. package/dist/video_source.d.ts.map +1 -1
  96. package/dist/video_source.js +4 -3
  97. package/dist/video_source.js.map +1 -1
  98. package/dist/video_stream.d.ts +1 -1
  99. package/dist/video_stream.d.ts.map +1 -1
  100. package/dist/video_stream.js +7 -3
  101. package/dist/video_stream.js.map +1 -1
  102. package/package.json +13 -10
  103. package/src/audio_frame.ts +6 -6
  104. package/src/audio_resampler.ts +10 -9
  105. package/src/audio_source.ts +9 -8
  106. package/src/audio_stream.ts +7 -6
  107. package/src/e2ee.ts +34 -34
  108. package/src/ffi_client.ts +23 -10
  109. package/src/index.ts +61 -2
  110. package/src/napi/native.d.ts +1 -0
  111. package/src/nodejs.rs +6 -3
  112. package/src/participant.ts +207 -47
  113. package/src/proto/audio_frame_pb.ts +562 -1279
  114. package/src/proto/e2ee_pb.ts +365 -886
  115. package/src/proto/ffi_pb.ts +206 -405
  116. package/src/proto/handle_pb.ts +21 -35
  117. package/src/proto/participant_pb.ts +71 -112
  118. package/src/proto/room_pb.ts +1284 -2995
  119. package/src/proto/rpc_pb.ts +310 -0
  120. package/src/proto/stats_pb.ts +1028 -1947
  121. package/src/proto/track_pb.ts +287 -621
  122. package/src/proto/video_frame_pb.ts +445 -905
  123. package/src/room.ts +181 -75
  124. package/src/rpc.ts +121 -0
  125. package/src/track.ts +8 -7
  126. package/src/track_publication.ts +5 -4
  127. package/src/version.ts +1 -0
  128. package/src/video_frame.ts +54 -27
  129. package/src/video_source.ts +7 -6
  130. package/src/video_stream.ts +7 -6
  131. package/dist/utils.d.ts +0 -7
  132. package/dist/utils.d.ts.map +0 -1
  133. package/dist/utils.js +0 -48
  134. package/dist/utils.js.map +0 -1
  135. package/src/utils.test.ts +0 -47
  136. package/src/utils.ts +0 -44
@@ -1,10 +1,10 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
+ import { create } from '@bufbuild/protobuf';
4
5
  import { FfiClient, FfiHandle } from './ffi_client.js';
5
6
  import type { OwnedParticipant, ParticipantInfo, ParticipantKind } from './proto/participant_pb.js';
6
- import {
7
- ChatMessage as ChatMessageModel,
7
+ import type {
8
8
  PublishDataCallback,
9
9
  PublishDataResponse,
10
10
  PublishSipDtmfCallback,
@@ -26,23 +26,38 @@ import {
26
26
  UnpublishTrackResponse,
27
27
  } from './proto/room_pb.js';
28
28
  import {
29
- EditChatMessageRequest,
30
- TranscriptionSegment as ProtoTranscriptionSegment,
31
- PublishDataRequest,
32
- PublishSipDtmfRequest,
33
- PublishTrackRequest,
34
- PublishTranscriptionRequest,
35
- SendChatMessageRequest,
36
- SetLocalAttributesRequest,
37
- SetLocalMetadataRequest,
38
- SetLocalNameRequest,
39
- UnpublishTrackRequest,
29
+ ChatMessageSchema,
30
+ EditChatMessageRequestSchema,
31
+ PublishDataRequestSchema,
32
+ PublishSipDtmfRequestSchema,
33
+ PublishTrackRequestSchema,
34
+ PublishTranscriptionRequestSchema,
35
+ SendChatMessageRequestSchema,
36
+ SetLocalAttributesRequestSchema,
37
+ SetLocalMetadataRequestSchema,
38
+ SetLocalNameRequestSchema,
39
+ UnpublishTrackRequestSchema,
40
40
  } from './proto/room_pb.js';
41
+ import { TranscriptionSegmentSchema } from './proto/room_pb.js';
42
+ import {
43
+ PerformRpcRequestSchema,
44
+ RegisterRpcMethodRequestSchema,
45
+ RpcMethodInvocationResponseRequestSchema,
46
+ UnregisterRpcMethodRequestSchema,
47
+ } from './proto/rpc_pb.js';
48
+ import type {
49
+ PerformRpcCallback,
50
+ PerformRpcResponse,
51
+ RegisterRpcMethodResponse,
52
+ RpcMethodInvocationResponseResponse,
53
+ UnregisterRpcMethodResponse,
54
+ } from './proto/rpc_pb.js';
55
+ import { type PerformRpcParams, RpcError, type RpcInvocationData } from './rpc.js';
41
56
  import type { LocalTrack } from './track.js';
42
57
  import type { RemoteTrackPublication, TrackPublication } from './track_publication.js';
43
58
  import { LocalTrackPublication } from './track_publication.js';
44
59
  import type { Transcription } from './transcription.js';
45
- import { ChatMessage } from './types.js';
60
+ import type { ChatMessage } from './types.js';
46
61
 
47
62
  export abstract class Participant {
48
63
  /** @internal */
@@ -54,8 +69,8 @@ export abstract class Participant {
54
69
  trackPublications = new Map<string, TrackPublication>();
55
70
 
56
71
  constructor(owned_info: OwnedParticipant) {
57
- this.info = owned_info.info;
58
- this.ffi_handle = new FfiHandle(owned_info.handle.id);
72
+ this.info = owned_info.info!;
73
+ this.ffi_handle = new FfiHandle(owned_info.handle!.id);
59
74
  }
60
75
 
61
76
  get sid(): string {
@@ -100,10 +115,12 @@ export type DataPublishOptions = {
100
115
  };
101
116
 
102
117
  export class LocalParticipant extends Participant {
118
+ private rpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>> = new Map();
119
+
103
120
  trackPublications: Map<string, LocalTrackPublication> = new Map();
104
121
 
105
122
  async publishData(data: Uint8Array, options: DataPublishOptions) {
106
- const req = new PublishDataRequest({
123
+ const req = create(PublishDataRequestSchema, {
107
124
  localParticipantHandle: this.ffi_handle.handle,
108
125
  dataPtr: FfiClient.instance.retrievePtr(data),
109
126
  dataLen: BigInt(data.byteLength),
@@ -126,7 +143,7 @@ export class LocalParticipant extends Participant {
126
143
  }
127
144
 
128
145
  async publishDtmf(code: number, digit: string) {
129
- const req = new PublishSipDtmfRequest({
146
+ const req = create(PublishSipDtmfRequestSchema, {
130
147
  localParticipantHandle: this.ffi_handle.handle,
131
148
  code,
132
149
  digit,
@@ -146,19 +163,18 @@ export class LocalParticipant extends Participant {
146
163
  }
147
164
 
148
165
  async publishTranscription(transcription: Transcription) {
149
- const req = new PublishTranscriptionRequest({
166
+ const req = create(PublishTranscriptionRequestSchema, {
150
167
  localParticipantHandle: this.ffi_handle.handle,
151
168
  participantIdentity: transcription.participantIdentity,
152
- segments: transcription.segments.map(
153
- (s) =>
154
- new ProtoTranscriptionSegment({
155
- id: s.id,
156
- text: s.text,
157
- startTime: s.startTime,
158
- endTime: s.endTime,
159
- final: s.final,
160
- language: s.language,
161
- }),
169
+ segments: transcription.segments.map((s) =>
170
+ create(TranscriptionSegmentSchema, {
171
+ id: s.id,
172
+ text: s.text,
173
+ startTime: s.startTime,
174
+ endTime: s.endTime,
175
+ final: s.final,
176
+ language: s.language,
177
+ }),
162
178
  ),
163
179
  trackId: transcription.trackSid,
164
180
  });
@@ -177,7 +193,7 @@ export class LocalParticipant extends Participant {
177
193
  }
178
194
 
179
195
  async updateMetadata(metadata: string) {
180
- const req = new SetLocalMetadataRequest({
196
+ const req = create(SetLocalMetadataRequestSchema, {
181
197
  localParticipantHandle: this.ffi_handle.handle,
182
198
  metadata: metadata,
183
199
  });
@@ -204,7 +220,7 @@ export class LocalParticipant extends Participant {
204
220
  destinationIdentities?: Array<string>,
205
221
  senderIdentity?: string,
206
222
  ): Promise<ChatMessage> {
207
- const req = new SendChatMessageRequest({
223
+ const req = create(SendChatMessageRequestSchema, {
208
224
  localParticipantHandle: this.ffi_handle.handle,
209
225
  message: text,
210
226
  destinationIdentities,
@@ -219,10 +235,10 @@ export class LocalParticipant extends Participant {
219
235
  return ev.message.case == 'chatMessage' && ev.message.value.asyncId == res.asyncId;
220
236
  });
221
237
 
222
- if (cb.error) {
223
- throw new Error(cb.error);
238
+ if (cb.message.case !== 'chatMessage') {
239
+ throw new Error(cb.message.value ?? 'Unknown Error');
224
240
  }
225
- const { id, timestamp, editTimestamp, message } = cb.chatMessage!;
241
+ const { id, timestamp, editTimestamp, message } = cb.message.value;
226
242
  return { id, timestamp: Number(timestamp), editTimestamp: Number(editTimestamp), message };
227
243
  }
228
244
 
@@ -235,10 +251,10 @@ export class LocalParticipant extends Participant {
235
251
  destinationIdentities?: Array<string>,
236
252
  senderIdentity?: string,
237
253
  ): Promise<ChatMessage> {
238
- const req = new EditChatMessageRequest({
254
+ const req = create(EditChatMessageRequestSchema, {
239
255
  localParticipantHandle: this.ffi_handle.handle,
240
256
  editText,
241
- originalMessage: new ChatMessageModel({
257
+ originalMessage: create(ChatMessageSchema, {
242
258
  ...originalMessage,
243
259
  timestamp: BigInt(originalMessage.timestamp),
244
260
  editTimestamp: originalMessage.editTimestamp
@@ -257,15 +273,15 @@ export class LocalParticipant extends Participant {
257
273
  return ev.message.case == 'chatMessage' && ev.message.value.asyncId == res.asyncId;
258
274
  });
259
275
 
260
- if (cb.error) {
261
- throw new Error(cb.error);
276
+ if (cb.message.case !== 'chatMessage') {
277
+ throw new Error(cb.message.value ?? 'Unknown Error');
262
278
  }
263
- const { id, timestamp, editTimestamp, message } = cb.chatMessage!;
279
+ const { id, timestamp, editTimestamp, message } = cb.message.value;
264
280
  return { id, timestamp: Number(timestamp), editTimestamp: Number(editTimestamp), message };
265
281
  }
266
282
 
267
283
  async updateName(name: string) {
268
- const req = new SetLocalNameRequest({
284
+ const req = create(SetLocalNameRequestSchema, {
269
285
  localParticipantHandle: this.ffi_handle.handle,
270
286
  name: name,
271
287
  });
@@ -280,9 +296,11 @@ export class LocalParticipant extends Participant {
280
296
  }
281
297
 
282
298
  async setAttributes(attributes: Record<string, string>) {
283
- const req = new SetLocalAttributesRequest({
299
+ const req = create(SetLocalAttributesRequestSchema, {
284
300
  localParticipantHandle: this.ffi_handle.handle,
285
- attributes: attributes,
301
+ attributes: Array.from(Object.entries(attributes)).map(([key, value]) => {
302
+ return { key, value };
303
+ }),
286
304
  });
287
305
 
288
306
  const res = FfiClient.instance.request<SetLocalAttributesResponse>({
@@ -298,7 +316,7 @@ export class LocalParticipant extends Participant {
298
316
  track: LocalTrack,
299
317
  options: TrackPublishOptions,
300
318
  ): Promise<LocalTrackPublication> {
301
- const req = new PublishTrackRequest({
319
+ const req = create(PublishTrackRequestSchema, {
302
320
  localParticipantHandle: this.ffi_handle.handle,
303
321
  trackHandle: track.ffi_handle.handle,
304
322
  options: options,
@@ -312,11 +330,11 @@ export class LocalParticipant extends Participant {
312
330
  return ev.message.case == 'publishTrack' && ev.message.value.asyncId == res.asyncId;
313
331
  });
314
332
 
315
- if (cb.error) {
316
- throw new Error(cb.error);
333
+ if (cb.message.case !== 'publication') {
334
+ throw new Error(cb.message.value ?? 'Unknown Error');
317
335
  }
318
336
 
319
- const track_publication = new LocalTrackPublication(cb.publication!);
337
+ const track_publication = new LocalTrackPublication(cb.message.value!);
320
338
  track_publication.track = track;
321
339
  this.trackPublications.set(track_publication.sid, track_publication);
322
340
 
@@ -324,7 +342,7 @@ export class LocalParticipant extends Participant {
324
342
  }
325
343
 
326
344
  async unpublishTrack(trackSid: string) {
327
- const req = new UnpublishTrackRequest({
345
+ const req = create(UnpublishTrackRequestSchema, {
328
346
  localParticipantHandle: this.ffi_handle.handle,
329
347
  trackSid: trackSid,
330
348
  });
@@ -347,6 +365,148 @@ export class LocalParticipant extends Participant {
347
365
  }
348
366
  this.trackPublications.delete(trackSid);
349
367
  }
368
+
369
+ /**
370
+ * Initiate an RPC call to a remote participant.
371
+ * @param params - Parameters for initiating the RPC call, see {@link PerformRpcParams}
372
+ * @returns A promise that resolves with the response payload or rejects with an error.
373
+ * @throws Error on failure. Details in `message`.
374
+ */
375
+ async performRpc({
376
+ destinationIdentity,
377
+ method,
378
+ payload,
379
+ responseTimeout,
380
+ }: PerformRpcParams): Promise<string> {
381
+ const req = create(PerformRpcRequestSchema, {
382
+ localParticipantHandle: this.ffi_handle.handle,
383
+ destinationIdentity,
384
+ method,
385
+ payload,
386
+ responseTimeoutMs: responseTimeout,
387
+ });
388
+
389
+ const res = FfiClient.instance.request<PerformRpcResponse>({
390
+ message: { case: 'performRpc', value: req },
391
+ });
392
+
393
+ const cb = await FfiClient.instance.waitFor<PerformRpcCallback>((ev) => {
394
+ return ev.message.case === 'performRpc' && ev.message.value.asyncId === res.asyncId;
395
+ });
396
+
397
+ if (cb.error) {
398
+ throw RpcError.fromProto(cb.error);
399
+ }
400
+
401
+ return cb.payload;
402
+ }
403
+
404
+ /**
405
+ * Establishes the participant as a receiver for calls of the specified RPC method.
406
+ * Will overwrite any existing callback for the same method.
407
+ *
408
+ * @param method - The name of the indicated RPC method
409
+ * @param handler - Will be invoked when an RPC request for this method is received
410
+ * @returns A promise that resolves when the method is successfully registered
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * room.localParticipant?.registerRpcMethod(
415
+ * 'greet',
416
+ * async (data: RpcInvocationData) => {
417
+ * console.log(`Received greeting from ${data.callerIdentity}: ${data.payload}`);
418
+ * return `Hello, ${data.callerIdentity}!`;
419
+ * }
420
+ * );
421
+ * ```
422
+ *
423
+ * See {@link RpcInvocationData} for more details on invocation params.
424
+ *
425
+ * The handler should return a Promise that resolves to a string.
426
+ * If unable to respond within `responseTimeout`, the request will result in an error on the caller's side.
427
+ *
428
+ * You may throw errors of type `RpcError` with a string `message` in the handler,
429
+ * and they will be received on the caller's side with the message intact.
430
+ * Other errors thrown in your handler will not be transmitted as-is, and will instead arrive to the caller as `1500` ("Application Error").
431
+ */
432
+ registerRpcMethod(method: string, handler: (data: RpcInvocationData) => Promise<string>) {
433
+ this.rpcHandlers.set(method, handler);
434
+
435
+ const req = create(RegisterRpcMethodRequestSchema, {
436
+ localParticipantHandle: this.ffi_handle.handle,
437
+ method,
438
+ });
439
+
440
+ FfiClient.instance.request<RegisterRpcMethodResponse>({
441
+ message: { case: 'registerRpcMethod', value: req },
442
+ });
443
+ }
444
+
445
+ /**
446
+ * Unregisters a previously registered RPC method.
447
+ *
448
+ * @param method - The name of the RPC method to unregister
449
+ */
450
+ unregisterRpcMethod(method: string) {
451
+ this.rpcHandlers.delete(method);
452
+
453
+ const req = create(UnregisterRpcMethodRequestSchema, {
454
+ localParticipantHandle: this.ffi_handle.handle,
455
+ method,
456
+ });
457
+
458
+ FfiClient.instance.request<UnregisterRpcMethodResponse>({
459
+ message: { case: 'unregisterRpcMethod', value: req },
460
+ });
461
+ }
462
+
463
+ /** @internal */
464
+ async handleRpcMethodInvocation(
465
+ invocationId: bigint,
466
+ method: string,
467
+ requestId: string,
468
+ callerIdentity: string,
469
+ payload: string,
470
+ responseTimeout: number,
471
+ ) {
472
+ let responseError: RpcError | null = null;
473
+ let responsePayload: string | null = null;
474
+
475
+ const handler = this.rpcHandlers.get(method);
476
+
477
+ if (!handler) {
478
+ responseError = RpcError.builtIn('UNSUPPORTED_METHOD');
479
+ } else {
480
+ try {
481
+ responsePayload = await handler({ requestId, callerIdentity, payload, responseTimeout });
482
+ } catch (error) {
483
+ if (error instanceof RpcError) {
484
+ responseError = error;
485
+ } else {
486
+ console.warn(
487
+ `Uncaught error returned by RPC handler for ${method}. Returning APPLICATION_ERROR instead.`,
488
+ error,
489
+ );
490
+ responseError = RpcError.builtIn('APPLICATION_ERROR');
491
+ }
492
+ }
493
+ }
494
+
495
+ const req = create(RpcMethodInvocationResponseRequestSchema, {
496
+ localParticipantHandle: this.ffi_handle.handle,
497
+ invocationId,
498
+ error: responseError ? responseError.toProto() : undefined,
499
+ payload: responsePayload ?? undefined,
500
+ });
501
+
502
+ const res = FfiClient.instance.request<RpcMethodInvocationResponseResponse>({
503
+ message: { case: 'rpcMethodInvocationResponse', value: req },
504
+ });
505
+
506
+ if (res.error) {
507
+ console.warn(`error sending rpc method invocation response: ${res.error}`);
508
+ }
509
+ }
350
510
  }
351
511
 
352
512
  export class RemoteParticipant extends Participant {