@livekit/rtc-node 0.8.1 → 0.9.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 (52) hide show
  1. package/dist/audio_source.d.ts +16 -1
  2. package/dist/audio_source.d.ts.map +1 -1
  3. package/dist/audio_source.js +50 -3
  4. package/dist/audio_source.js.map +1 -1
  5. package/dist/audio_stream.d.ts +10 -13
  6. package/dist/audio_stream.d.ts.map +1 -1
  7. package/dist/audio_stream.js +34 -8
  8. package/dist/audio_stream.js.map +1 -1
  9. package/dist/ffi_client.d.ts +1 -1
  10. package/dist/ffi_client.d.ts.map +1 -1
  11. package/dist/ffi_client.js.map +1 -1
  12. package/dist/index.d.ts +3 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +3 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/napi/native.d.ts +5 -8
  17. package/dist/participant.d.ts +2 -1
  18. package/dist/participant.d.ts.map +1 -1
  19. package/dist/participant.js +3 -0
  20. package/dist/participant.js.map +1 -1
  21. package/dist/proto/audio_frame_pb.d.ts +32 -2
  22. package/dist/proto/audio_frame_pb.d.ts.map +1 -1
  23. package/dist/proto/audio_frame_pb.js +59 -1
  24. package/dist/proto/audio_frame_pb.js.map +1 -1
  25. package/dist/proto/ffi_pb.d.ts +21 -9
  26. package/dist/proto/ffi_pb.d.ts.map +1 -1
  27. package/dist/proto/ffi_pb.js +11 -9
  28. package/dist/proto/ffi_pb.js.map +1 -1
  29. package/dist/room.d.ts +1 -1
  30. package/dist/room.d.ts.map +1 -1
  31. package/dist/room.js +0 -3
  32. package/dist/room.js.map +1 -1
  33. package/dist/utils.d.ts +7 -0
  34. package/dist/utils.d.ts.map +1 -0
  35. package/dist/utils.js +41 -0
  36. package/dist/utils.js.map +1 -0
  37. package/dist/video_stream.d.ts +10 -10
  38. package/dist/video_stream.d.ts.map +1 -1
  39. package/dist/video_stream.js +35 -11
  40. package/dist/video_stream.js.map +1 -1
  41. package/package.json +7 -7
  42. package/src/audio_source.ts +70 -2
  43. package/src/audio_stream.ts +36 -17
  44. package/src/ffi_client.ts +1 -1
  45. package/src/index.ts +3 -2
  46. package/src/napi/native.d.ts +5 -8
  47. package/src/participant.ts +5 -1
  48. package/src/proto/audio_frame_pb.ts +71 -3
  49. package/src/proto/ffi_pb.ts +31 -17
  50. package/src/room.ts +1 -1
  51. package/src/utils.ts +36 -0
  52. package/src/video_stream.ts +37 -13
@@ -22,7 +22,7 @@ import { Message, proto3, protoInt64 } from "@bufbuild/protobuf";
22
22
  import { ConnectCallback, ConnectRequest, ConnectResponse, DisconnectCallback, DisconnectRequest, DisconnectResponse, GetSessionStatsCallback, GetSessionStatsRequest, GetSessionStatsResponse, PublishDataCallback, PublishDataRequest, PublishDataResponse, PublishSipDtmfCallback, PublishSipDtmfRequest, PublishSipDtmfResponse, PublishTrackCallback, PublishTrackRequest, PublishTrackResponse, PublishTranscriptionCallback, PublishTranscriptionRequest, PublishTranscriptionResponse, RoomEvent, SetLocalAttributesCallback, SetLocalAttributesRequest, SetLocalAttributesResponse, SetLocalMetadataCallback, SetLocalMetadataRequest, SetLocalMetadataResponse, SetLocalNameCallback, SetLocalNameRequest, SetLocalNameResponse, SetSubscribedRequest, SetSubscribedResponse, UnpublishTrackCallback, UnpublishTrackRequest, UnpublishTrackResponse } from "./room_pb.js";
23
23
  import { CreateAudioTrackRequest, CreateAudioTrackResponse, CreateVideoTrackRequest, CreateVideoTrackResponse, EnableRemoteTrackRequest, EnableRemoteTrackResponse, GetStatsCallback, GetStatsRequest, GetStatsResponse, LocalTrackMuteRequest, LocalTrackMuteResponse, TrackEvent } from "./track_pb.js";
24
24
  import { CaptureVideoFrameRequest, CaptureVideoFrameResponse, NewVideoSourceRequest, NewVideoSourceResponse, NewVideoStreamRequest, NewVideoStreamResponse, VideoConvertRequest, VideoConvertResponse, VideoStreamEvent, VideoStreamFromParticipantRequest, VideoStreamFromParticipantResponse } from "./video_frame_pb.js";
25
- import { AudioStreamEvent, AudioStreamFromParticipantRequest, AudioStreamFromParticipantResponse, CaptureAudioFrameCallback, CaptureAudioFrameRequest, CaptureAudioFrameResponse, NewAudioResamplerRequest, NewAudioResamplerResponse, NewAudioSourceRequest, NewAudioSourceResponse, NewAudioStreamRequest, NewAudioStreamResponse, RemixAndResampleRequest, RemixAndResampleResponse } from "./audio_frame_pb.js";
25
+ import { AudioStreamEvent, AudioStreamFromParticipantRequest, AudioStreamFromParticipantResponse, CaptureAudioFrameCallback, CaptureAudioFrameRequest, CaptureAudioFrameResponse, ClearAudioBufferRequest, ClearAudioBufferResponse, NewAudioResamplerRequest, NewAudioResamplerResponse, NewAudioSourceRequest, NewAudioSourceResponse, NewAudioStreamRequest, NewAudioStreamResponse, RemixAndResampleRequest, RemixAndResampleResponse } from "./audio_frame_pb.js";
26
26
  import { E2eeRequest, E2eeResponse } from "./e2ee_pb.js";
27
27
 
28
28
  /**
@@ -239,25 +239,31 @@ export class FfiRequest extends Message<FfiRequest> {
239
239
  case: "captureAudioFrame";
240
240
  } | {
241
241
  /**
242
- * @generated from field: livekit.proto.NewAudioResamplerRequest new_audio_resampler = 28;
242
+ * @generated from field: livekit.proto.ClearAudioBufferRequest clear_audio_buffer = 28;
243
+ */
244
+ value: ClearAudioBufferRequest;
245
+ case: "clearAudioBuffer";
246
+ } | {
247
+ /**
248
+ * @generated from field: livekit.proto.NewAudioResamplerRequest new_audio_resampler = 29;
243
249
  */
244
250
  value: NewAudioResamplerRequest;
245
251
  case: "newAudioResampler";
246
252
  } | {
247
253
  /**
248
- * @generated from field: livekit.proto.RemixAndResampleRequest remix_and_resample = 29;
254
+ * @generated from field: livekit.proto.RemixAndResampleRequest remix_and_resample = 30;
249
255
  */
250
256
  value: RemixAndResampleRequest;
251
257
  case: "remixAndResample";
252
258
  } | {
253
259
  /**
254
- * @generated from field: livekit.proto.E2eeRequest e2ee = 30;
260
+ * @generated from field: livekit.proto.E2eeRequest e2ee = 31;
255
261
  */
256
262
  value: E2eeRequest;
257
263
  case: "e2ee";
258
264
  } | {
259
265
  /**
260
- * @generated from field: livekit.proto.AudioStreamFromParticipantRequest audio_stream_from_participant = 31;
266
+ * @generated from field: livekit.proto.AudioStreamFromParticipantRequest audio_stream_from_participant = 32;
261
267
  */
262
268
  value: AudioStreamFromParticipantRequest;
263
269
  case: "audioStreamFromParticipant";
@@ -297,10 +303,11 @@ export class FfiRequest extends Message<FfiRequest> {
297
303
  { no: 25, name: "new_audio_stream", kind: "message", T: NewAudioStreamRequest, oneof: "message" },
298
304
  { no: 26, name: "new_audio_source", kind: "message", T: NewAudioSourceRequest, oneof: "message" },
299
305
  { no: 27, name: "capture_audio_frame", kind: "message", T: CaptureAudioFrameRequest, oneof: "message" },
300
- { no: 28, name: "new_audio_resampler", kind: "message", T: NewAudioResamplerRequest, oneof: "message" },
301
- { no: 29, name: "remix_and_resample", kind: "message", T: RemixAndResampleRequest, oneof: "message" },
302
- { no: 30, name: "e2ee", kind: "message", T: E2eeRequest, oneof: "message" },
303
- { no: 31, name: "audio_stream_from_participant", kind: "message", T: AudioStreamFromParticipantRequest, oneof: "message" },
306
+ { no: 28, name: "clear_audio_buffer", kind: "message", T: ClearAudioBufferRequest, oneof: "message" },
307
+ { no: 29, name: "new_audio_resampler", kind: "message", T: NewAudioResamplerRequest, oneof: "message" },
308
+ { no: 30, name: "remix_and_resample", kind: "message", T: RemixAndResampleRequest, oneof: "message" },
309
+ { no: 31, name: "e2ee", kind: "message", T: E2eeRequest, oneof: "message" },
310
+ { no: 32, name: "audio_stream_from_participant", kind: "message", T: AudioStreamFromParticipantRequest, oneof: "message" },
304
311
  ]);
305
312
 
306
313
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): FfiRequest {
@@ -495,25 +502,31 @@ export class FfiResponse extends Message<FfiResponse> {
495
502
  case: "captureAudioFrame";
496
503
  } | {
497
504
  /**
498
- * @generated from field: livekit.proto.NewAudioResamplerResponse new_audio_resampler = 28;
505
+ * @generated from field: livekit.proto.ClearAudioBufferResponse clear_audio_buffer = 28;
506
+ */
507
+ value: ClearAudioBufferResponse;
508
+ case: "clearAudioBuffer";
509
+ } | {
510
+ /**
511
+ * @generated from field: livekit.proto.NewAudioResamplerResponse new_audio_resampler = 29;
499
512
  */
500
513
  value: NewAudioResamplerResponse;
501
514
  case: "newAudioResampler";
502
515
  } | {
503
516
  /**
504
- * @generated from field: livekit.proto.RemixAndResampleResponse remix_and_resample = 29;
517
+ * @generated from field: livekit.proto.RemixAndResampleResponse remix_and_resample = 30;
505
518
  */
506
519
  value: RemixAndResampleResponse;
507
520
  case: "remixAndResample";
508
521
  } | {
509
522
  /**
510
- * @generated from field: livekit.proto.AudioStreamFromParticipantResponse audio_stream_from_participant = 30;
523
+ * @generated from field: livekit.proto.AudioStreamFromParticipantResponse audio_stream_from_participant = 31;
511
524
  */
512
525
  value: AudioStreamFromParticipantResponse;
513
526
  case: "audioStreamFromParticipant";
514
527
  } | {
515
528
  /**
516
- * @generated from field: livekit.proto.E2eeResponse e2ee = 31;
529
+ * @generated from field: livekit.proto.E2eeResponse e2ee = 32;
517
530
  */
518
531
  value: E2eeResponse;
519
532
  case: "e2ee";
@@ -553,10 +566,11 @@ export class FfiResponse extends Message<FfiResponse> {
553
566
  { no: 25, name: "new_audio_stream", kind: "message", T: NewAudioStreamResponse, oneof: "message" },
554
567
  { no: 26, name: "new_audio_source", kind: "message", T: NewAudioSourceResponse, oneof: "message" },
555
568
  { no: 27, name: "capture_audio_frame", kind: "message", T: CaptureAudioFrameResponse, oneof: "message" },
556
- { no: 28, name: "new_audio_resampler", kind: "message", T: NewAudioResamplerResponse, oneof: "message" },
557
- { no: 29, name: "remix_and_resample", kind: "message", T: RemixAndResampleResponse, oneof: "message" },
558
- { no: 30, name: "audio_stream_from_participant", kind: "message", T: AudioStreamFromParticipantResponse, oneof: "message" },
559
- { no: 31, name: "e2ee", kind: "message", T: E2eeResponse, oneof: "message" },
569
+ { no: 28, name: "clear_audio_buffer", kind: "message", T: ClearAudioBufferResponse, oneof: "message" },
570
+ { no: 29, name: "new_audio_resampler", kind: "message", T: NewAudioResamplerResponse, oneof: "message" },
571
+ { no: 30, name: "remix_and_resample", kind: "message", T: RemixAndResampleResponse, oneof: "message" },
572
+ { no: 31, name: "audio_stream_from_participant", kind: "message", T: AudioStreamFromParticipantResponse, oneof: "message" },
573
+ { no: 32, name: "e2ee", kind: "message", T: E2eeResponse, oneof: "message" },
560
574
  ]);
561
575
 
562
576
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): FfiResponse {
package/src/room.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
+ import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
4
5
  import EventEmitter from 'events';
5
- import type TypedEmitter from 'typed-emitter';
6
6
  import type { E2EEOptions } from './e2ee.js';
7
7
  import { E2EEManager } from './e2ee.js';
8
8
  import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
package/src/utils.ts ADDED
@@ -0,0 +1,36 @@
1
+ // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ export class Mutex {
5
+ #locking: Promise<void>;
6
+ #locks: number;
7
+ #limit: number;
8
+
9
+ constructor(limit = 1) {
10
+ this.#locking = Promise.resolve();
11
+ this.#locks = 0;
12
+ this.#limit = limit;
13
+ }
14
+
15
+ isLocked(): boolean {
16
+ return this.#locks >= this.#limit;
17
+ }
18
+
19
+ async lock(): Promise<() => void> {
20
+ this.#locks += 1;
21
+
22
+ let unlockNext: () => void;
23
+
24
+ const willLock = new Promise<void>(
25
+ (resolve) =>
26
+ (unlockNext = () => {
27
+ this.#locks -= 1;
28
+ resolve();
29
+ }),
30
+ );
31
+
32
+ const willUnlock = this.#locking.then(() => unlockNext);
33
+ this.#locking = this.#locking.then(() => willLock);
34
+ return willUnlock;
35
+ }
36
+ }
@@ -1,8 +1,6 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
- import EventEmitter from 'events';
5
- import type TypedEmitter from 'typed-emitter';
6
4
  import type { FfiEvent } from './ffi_client.js';
7
5
  import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
8
6
  import type {
@@ -12,6 +10,7 @@ import type {
12
10
  } from './proto/video_frame_pb.js';
13
11
  import { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js';
14
12
  import type { Track } from './track.js';
13
+ import { Mutex } from './utils.js';
15
14
  import { VideoFrame } from './video_frame.js';
16
15
 
17
16
  export type VideoFrameEvent = {
@@ -20,24 +19,21 @@ export type VideoFrameEvent = {
20
19
  rotation: VideoRotation;
21
20
  };
22
21
 
23
- export type VideoStreamCallbacks = {
24
- frameReceived: (evt: VideoFrameEvent) => void;
25
- };
26
-
27
- export enum VideoStreamEvent {
28
- FrameReceived = 'frameReceived',
29
- }
30
-
31
- export class VideoStream extends (EventEmitter as new () => TypedEmitter<VideoStreamCallbacks>) {
22
+ export class VideoStream implements AsyncIterableIterator<VideoFrameEvent> {
32
23
  /** @internal */
33
24
  info: VideoStreamInfo;
34
25
  /** @internal */
35
26
  ffiHandle: FfiHandle;
27
+ /** @internal */
28
+ eventQueue: (VideoFrameEvent | null)[] = [];
29
+ /** @internal */
30
+ queueResolve: ((value: IteratorResult<VideoFrameEvent>) => void) | null = null;
31
+ /** @internal */
32
+ mutex = new Mutex();
36
33
 
37
34
  track: Track;
38
35
 
39
36
  constructor(track: Track) {
40
- super();
41
37
  this.track = track;
42
38
 
43
39
  const req = new NewVideoStreamRequest({
@@ -72,7 +68,12 @@ export class VideoStream extends (EventEmitter as new () => TypedEmitter<VideoSt
72
68
  const rotation = streamEvent.value.rotation;
73
69
  const timestampUs = streamEvent.value.timestampUs;
74
70
  const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer);
75
- this.emit(VideoStreamEvent.FrameReceived, { frame, timestampUs, rotation });
71
+ const value = { rotation, timestampUs, frame };
72
+ if (this.queueResolve) {
73
+ this.queueResolve({ done: false, value });
74
+ } else {
75
+ this.eventQueue.push(value);
76
+ }
76
77
  break;
77
78
  case 'eos':
78
79
  FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
@@ -80,7 +81,30 @@ export class VideoStream extends (EventEmitter as new () => TypedEmitter<VideoSt
80
81
  }
81
82
  };
82
83
 
84
+ async next(): Promise<IteratorResult<VideoFrameEvent>> {
85
+ const unlock = await this.mutex.lock();
86
+ if (this.eventQueue.length > 0) {
87
+ unlock();
88
+ const value = this.eventQueue.shift();
89
+ if (value) {
90
+ return { done: false, value };
91
+ } else {
92
+ return { done: true, value: undefined };
93
+ }
94
+ }
95
+ const promise = new Promise<IteratorResult<VideoFrameEvent>>(
96
+ (resolve) => (this.queueResolve = resolve),
97
+ );
98
+ unlock();
99
+ return promise;
100
+ }
101
+
83
102
  close() {
103
+ this.eventQueue.push(null);
84
104
  this.ffiHandle.dispose();
85
105
  }
106
+
107
+ [Symbol.asyncIterator](): VideoStream {
108
+ return this;
109
+ }
86
110
  }