@livekit/rtc-node 0.13.11 → 0.13.12

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.
@@ -1,14 +1,10 @@
1
1
  // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
- import { Mutex } from '@livekit/mutex';
4
+ import { ReadableStream, type UnderlyingSource } from 'node:stream/web';
5
5
  import type { FfiEvent } from './ffi_client.js';
6
6
  import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
7
- import type {
8
- NewVideoStreamResponse,
9
- VideoRotation,
10
- VideoStreamInfo,
11
- } from './proto/video_frame_pb.js';
7
+ import type { NewVideoStreamResponse, VideoRotation } from './proto/video_frame_pb.js';
12
8
  import { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js';
13
9
  import type { Track } from './track.js';
14
10
  import { VideoFrame } from './video_frame.js';
@@ -19,23 +15,11 @@ export type VideoFrameEvent = {
19
15
  rotation: VideoRotation;
20
16
  };
21
17
 
22
- export class VideoStream implements AsyncIterableIterator<VideoFrameEvent> {
23
- /** @internal */
24
- info?: VideoStreamInfo;
25
- /** @internal */
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();
33
-
34
- track: Track;
18
+ class VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {
19
+ private controller?: ReadableStreamDefaultController<VideoFrameEvent>;
20
+ private ffiHandle: FfiHandle;
35
21
 
36
22
  constructor(track: Track) {
37
- this.track = track;
38
-
39
23
  const req = new NewVideoStreamRequest({
40
24
  type: VideoStreamType.VIDEO_STREAM_NATIVE,
41
25
  trackHandle: track.ffi_handle.handle,
@@ -48,13 +32,15 @@ export class VideoStream implements AsyncIterableIterator<VideoFrameEvent> {
48
32
  },
49
33
  });
50
34
 
51
- this.info = res.stream?.info;
52
35
  this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);
53
-
54
36
  FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);
55
37
  }
56
38
 
57
39
  private onEvent = (ev: FfiEvent) => {
40
+ if (!this.controller) {
41
+ throw new Error('Stream controller not initialized');
42
+ }
43
+
58
44
  if (
59
45
  ev.message.case != 'videoStreamEvent' ||
60
46
  ev.message.value.streamHandle != this.ffiHandle.handle
@@ -69,54 +55,32 @@ export class VideoStream implements AsyncIterableIterator<VideoFrameEvent> {
69
55
  const timestampUs = streamEvent.value.timestampUs;
70
56
  const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);
71
57
  const value = { rotation, timestampUs, frame };
72
- if (this.queueResolve) {
73
- this.queueResolve({
74
- done: false,
75
- value: {
76
- frame: value.frame,
77
- timestampUs: value.timestampUs!,
78
- rotation: value.rotation!,
79
- },
80
- });
81
- this.queueResolve = null;
82
- } else {
83
- this.eventQueue.push({
84
- frame: value.frame,
85
- timestampUs: value.timestampUs!,
86
- rotation: value.rotation!,
87
- });
88
- }
58
+ const videoFrameEvent = {
59
+ frame: value.frame,
60
+ timestampUs: value.timestampUs!,
61
+ rotation: value.rotation!,
62
+ };
63
+ this.controller.enqueue(videoFrameEvent);
89
64
  break;
90
65
  case 'eos':
91
66
  FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
67
+ this.controller.close();
92
68
  break;
93
69
  }
94
70
  };
95
71
 
96
- async next(): Promise<IteratorResult<VideoFrameEvent>> {
97
- const unlock = await this.mutex.lock();
98
- if (this.eventQueue.length > 0) {
99
- unlock();
100
- const value = this.eventQueue.shift();
101
- if (value) {
102
- return { done: false, value };
103
- } else {
104
- return { done: true, value: undefined };
105
- }
106
- }
107
- const promise = new Promise<IteratorResult<VideoFrameEvent>>(
108
- (resolve) => (this.queueResolve = resolve),
109
- );
110
- unlock();
111
- return promise;
72
+ start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {
73
+ this.controller = controller;
112
74
  }
113
75
 
114
- close() {
115
- this.eventQueue.push(null);
76
+ cancel() {
77
+ FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
116
78
  this.ffiHandle.dispose();
117
79
  }
80
+ }
118
81
 
119
- [Symbol.asyncIterator](): VideoStream {
120
- return this;
82
+ export class VideoStream extends ReadableStream<VideoFrameEvent> {
83
+ constructor(track: Track) {
84
+ super(new VideoStreamSource(track));
121
85
  }
122
86
  }