@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.
- package/dist/audio_filter.cjs.map +1 -1
- package/dist/audio_filter.d.ts.map +1 -1
- package/dist/audio_filter.js +1 -4
- package/dist/audio_filter.js.map +1 -1
- package/dist/audio_source.cjs +5 -1
- package/dist/audio_source.cjs.map +1 -1
- package/dist/audio_source.d.ts.map +1 -1
- package/dist/audio_source.js +5 -1
- package/dist/audio_source.js.map +1 -1
- package/dist/audio_stream.cjs +15 -36
- package/dist/audio_stream.cjs.map +1 -1
- package/dist/audio_stream.d.cts +4 -22
- package/dist/audio_stream.d.ts +4 -22
- package/dist/audio_stream.d.ts.map +1 -1
- package/dist/audio_stream.js +15 -36
- package/dist/audio_stream.js.map +1 -1
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -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/dist/video_stream.cjs +20 -48
- package/dist/video_stream.cjs.map +1 -1
- package/dist/video_stream.d.cts +4 -19
- package/dist/video_stream.d.ts +4 -19
- package/dist/video_stream.d.ts.map +1 -1
- package/dist/video_stream.js +20 -48
- package/dist/video_stream.js.map +1 -1
- package/package.json +6 -6
- package/src/audio_filter.ts +2 -4
- package/src/audio_source.ts +7 -3
- package/src/audio_stream.ts +30 -51
- package/src/version.ts +1 -1
- package/src/video_stream.ts +24 -60
package/dist/video_stream.cjs
CHANGED
|
@@ -21,19 +21,16 @@ __export(video_stream_exports, {
|
|
|
21
21
|
VideoStream: () => VideoStream
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(video_stream_exports);
|
|
24
|
-
var
|
|
24
|
+
var import_web = require("node:stream/web");
|
|
25
25
|
var import_ffi_client = require("./ffi_client.cjs");
|
|
26
26
|
var import_video_frame_pb = require("./proto/video_frame_pb.cjs");
|
|
27
27
|
var import_video_frame = require("./video_frame.cjs");
|
|
28
|
-
class
|
|
28
|
+
class VideoStreamSource {
|
|
29
29
|
constructor(track) {
|
|
30
|
-
/** @internal */
|
|
31
|
-
this.eventQueue = [];
|
|
32
|
-
/** @internal */
|
|
33
|
-
this.queueResolve = null;
|
|
34
|
-
/** @internal */
|
|
35
|
-
this.mutex = new import_mutex.Mutex();
|
|
36
30
|
this.onEvent = (ev) => {
|
|
31
|
+
if (!this.controller) {
|
|
32
|
+
throw new Error("Stream controller not initialized");
|
|
33
|
+
}
|
|
37
34
|
if (ev.message.case != "videoStreamEvent" || ev.message.value.streamHandle != this.ffiHandle.handle) {
|
|
38
35
|
return;
|
|
39
36
|
}
|
|
@@ -44,31 +41,19 @@ class VideoStream {
|
|
|
44
41
|
const timestampUs = streamEvent.value.timestampUs;
|
|
45
42
|
const frame = import_video_frame.VideoFrame.fromOwnedInfo(streamEvent.value.buffer);
|
|
46
43
|
const value = { rotation, timestampUs, frame };
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
rotation: value.rotation
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
this.queueResolve = null;
|
|
57
|
-
} else {
|
|
58
|
-
this.eventQueue.push({
|
|
59
|
-
frame: value.frame,
|
|
60
|
-
timestampUs: value.timestampUs,
|
|
61
|
-
rotation: value.rotation
|
|
62
|
-
});
|
|
63
|
-
}
|
|
44
|
+
const videoFrameEvent = {
|
|
45
|
+
frame: value.frame,
|
|
46
|
+
timestampUs: value.timestampUs,
|
|
47
|
+
rotation: value.rotation
|
|
48
|
+
};
|
|
49
|
+
this.controller.enqueue(videoFrameEvent);
|
|
64
50
|
break;
|
|
65
51
|
case "eos":
|
|
66
52
|
import_ffi_client.FfiClient.instance.off(import_ffi_client.FfiClientEvent.FfiEvent, this.onEvent);
|
|
53
|
+
this.controller.close();
|
|
67
54
|
break;
|
|
68
55
|
}
|
|
69
56
|
};
|
|
70
|
-
var _a;
|
|
71
|
-
this.track = track;
|
|
72
57
|
const req = new import_video_frame_pb.NewVideoStreamRequest({
|
|
73
58
|
type: import_video_frame_pb.VideoStreamType.VIDEO_STREAM_NATIVE,
|
|
74
59
|
trackHandle: track.ffi_handle.handle
|
|
@@ -79,33 +64,20 @@ class VideoStream {
|
|
|
79
64
|
value: req
|
|
80
65
|
}
|
|
81
66
|
});
|
|
82
|
-
this.info = (_a = res.stream) == null ? void 0 : _a.info;
|
|
83
67
|
this.ffiHandle = new import_ffi_client.FfiHandle(res.stream.handle.id);
|
|
84
68
|
import_ffi_client.FfiClient.instance.on(import_ffi_client.FfiClientEvent.FfiEvent, this.onEvent);
|
|
85
69
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (this.eventQueue.length > 0) {
|
|
89
|
-
unlock();
|
|
90
|
-
const value = this.eventQueue.shift();
|
|
91
|
-
if (value) {
|
|
92
|
-
return { done: false, value };
|
|
93
|
-
} else {
|
|
94
|
-
return { done: true, value: void 0 };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const promise = new Promise(
|
|
98
|
-
(resolve) => this.queueResolve = resolve
|
|
99
|
-
);
|
|
100
|
-
unlock();
|
|
101
|
-
return promise;
|
|
70
|
+
start(controller) {
|
|
71
|
+
this.controller = controller;
|
|
102
72
|
}
|
|
103
|
-
|
|
104
|
-
|
|
73
|
+
cancel() {
|
|
74
|
+
import_ffi_client.FfiClient.instance.off(import_ffi_client.FfiClientEvent.FfiEvent, this.onEvent);
|
|
105
75
|
this.ffiHandle.dispose();
|
|
106
76
|
}
|
|
107
|
-
|
|
108
|
-
|
|
77
|
+
}
|
|
78
|
+
class VideoStream extends import_web.ReadableStream {
|
|
79
|
+
constructor(track) {
|
|
80
|
+
super(new VideoStreamSource(track));
|
|
109
81
|
}
|
|
110
82
|
}
|
|
111
83
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { ReadableStream, type UnderlyingSource } from 'node:stream/web';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport type { NewVideoStreamResponse, VideoRotation } from './proto/video_frame_pb.js';\nimport { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js';\nimport type { Track } from './track.js';\nimport { VideoFrame } from './video_frame.js';\n\nexport type VideoFrameEvent = {\n frame: VideoFrame;\n timestampUs: bigint;\n rotation: VideoRotation;\n};\n\nclass VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {\n private controller?: ReadableStreamDefaultController<VideoFrameEvent>;\n private ffiHandle: FfiHandle;\n\n constructor(track: Track) {\n const req = new NewVideoStreamRequest({\n type: VideoStreamType.VIDEO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n });\n\n const res = FfiClient.instance.request<NewVideoStreamResponse>({\n message: {\n case: 'newVideoStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\n }\n\n private onEvent = (ev: FfiEvent) => {\n if (!this.controller) {\n throw new Error('Stream controller not initialized');\n }\n\n if (\n ev.message.case != 'videoStreamEvent' ||\n ev.message.value.streamHandle != this.ffiHandle.handle\n ) {\n return;\n }\n\n const streamEvent = ev.message.value.message;\n switch (streamEvent.case) {\n case 'frameReceived':\n const rotation = streamEvent.value.rotation;\n const timestampUs = streamEvent.value.timestampUs;\n const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);\n const value = { rotation, timestampUs, frame };\n const videoFrameEvent = {\n frame: value.frame,\n timestampUs: value.timestampUs!,\n rotation: value.rotation!,\n };\n this.controller.enqueue(videoFrameEvent);\n break;\n case 'eos':\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.controller.close();\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {\n this.controller = controller;\n }\n\n cancel() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.ffiHandle.dispose();\n }\n}\n\nexport class VideoStream extends ReadableStream<VideoFrameEvent> {\n constructor(track: Track) {\n super(new VideoStreamSource(track));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBAAsD;AAEtD,wBAAqD;AAErD,4BAAuD;AAEvD,yBAA2B;AAQ3B,MAAM,kBAA+D;AAAA,EAInE,YAAY,OAAc;AAiB1B,SAAQ,UAAU,CAAC,OAAiB;AAClC,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AAEA,UACE,GAAG,QAAQ,QAAQ,sBACnB,GAAG,QAAQ,MAAM,gBAAgB,KAAK,UAAU,QAChD;AACA;AAAA,MACF;AAEA,YAAM,cAAc,GAAG,QAAQ,MAAM;AACrC,cAAQ,YAAY,MAAM;AAAA,QACxB,KAAK;AACH,gBAAM,WAAW,YAAY,MAAM;AACnC,gBAAM,cAAc,YAAY,MAAM;AACtC,gBAAM,QAAQ,8BAAW,cAAc,YAAY,MAAM,MAAO;AAChE,gBAAM,QAAQ,EAAE,UAAU,aAAa,MAAM;AAC7C,gBAAM,kBAAkB;AAAA,YACtB,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,UAAU,MAAM;AAAA,UAClB;AACA,eAAK,WAAW,QAAQ,eAAe;AACvC;AAAA,QACF,KAAK;AACH,sCAAU,SAAS,IAAI,iCAAe,UAAU,KAAK,OAAO;AAC5D,eAAK,WAAW,MAAM;AACtB;AAAA,MACJ;AAAA,IACF;AA/CE,UAAM,MAAM,IAAI,4CAAsB;AAAA,MACpC,MAAM,sCAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,4BAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,YAAY,IAAI,4BAAU,IAAI,OAAQ,OAAQ,EAAG;AACtD,gCAAU,SAAS,GAAG,iCAAe,UAAU,KAAK,OAAO;AAAA,EAC7D;AAAA,EAmCA,MAAM,YAA8D;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,SAAS;AACP,gCAAU,SAAS,IAAI,iCAAe,UAAU,KAAK,OAAO;AAC5D,SAAK,UAAU,QAAQ;AAAA,EACzB;AACF;AAEO,MAAM,oBAAoB,0BAAgC;AAAA,EAC/D,YAAY,OAAc;AACxB,UAAM,IAAI,kBAAkB,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
|
package/dist/video_stream.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { VideoRotation, VideoStreamInfo } from './proto/video_frame_pb.cjs';
|
|
1
|
+
import { ReadableStream } from 'node:stream/web';
|
|
2
|
+
import { VideoRotation } from './proto/video_frame_pb.cjs';
|
|
4
3
|
import { Track } from './track.cjs';
|
|
5
4
|
import { VideoFrame } from './video_frame.cjs';
|
|
6
5
|
import '@bufbuild/protobuf';
|
|
@@ -11,6 +10,7 @@ import './proto/handle_pb.cjs';
|
|
|
11
10
|
import './audio_source.cjs';
|
|
12
11
|
import './audio_frame.cjs';
|
|
13
12
|
import './proto/audio_frame_pb.cjs';
|
|
13
|
+
import './napi/native.d.cjs';
|
|
14
14
|
import './video_source.cjs';
|
|
15
15
|
|
|
16
16
|
type VideoFrameEvent = {
|
|
@@ -18,23 +18,8 @@ type VideoFrameEvent = {
|
|
|
18
18
|
timestampUs: bigint;
|
|
19
19
|
rotation: VideoRotation;
|
|
20
20
|
};
|
|
21
|
-
declare class VideoStream
|
|
22
|
-
/** @internal */
|
|
23
|
-
info?: VideoStreamInfo;
|
|
24
|
-
/** @internal */
|
|
25
|
-
ffiHandle: FfiHandle;
|
|
26
|
-
/** @internal */
|
|
27
|
-
eventQueue: (VideoFrameEvent | null)[];
|
|
28
|
-
/** @internal */
|
|
29
|
-
queueResolve: ((value: IteratorResult<VideoFrameEvent>) => void) | null;
|
|
30
|
-
/** @internal */
|
|
31
|
-
mutex: Mutex;
|
|
32
|
-
track: Track;
|
|
21
|
+
declare class VideoStream extends ReadableStream<VideoFrameEvent> {
|
|
33
22
|
constructor(track: Track);
|
|
34
|
-
private onEvent;
|
|
35
|
-
next(): Promise<IteratorResult<VideoFrameEvent>>;
|
|
36
|
-
close(): void;
|
|
37
|
-
[Symbol.asyncIterator](): VideoStream;
|
|
38
23
|
}
|
|
39
24
|
|
|
40
25
|
export { type VideoFrameEvent, VideoStream };
|
package/dist/video_stream.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { VideoRotation, VideoStreamInfo } from './proto/video_frame_pb.js';
|
|
1
|
+
import { ReadableStream } from 'node:stream/web';
|
|
2
|
+
import { VideoRotation } from './proto/video_frame_pb.js';
|
|
4
3
|
import { Track } from './track.js';
|
|
5
4
|
import { VideoFrame } from './video_frame.js';
|
|
6
5
|
import '@bufbuild/protobuf';
|
|
@@ -11,6 +10,7 @@ import './proto/handle_pb.js';
|
|
|
11
10
|
import './audio_source.js';
|
|
12
11
|
import './audio_frame.js';
|
|
13
12
|
import './proto/audio_frame_pb.js';
|
|
13
|
+
import './napi/native.d.js';
|
|
14
14
|
import './video_source.js';
|
|
15
15
|
|
|
16
16
|
type VideoFrameEvent = {
|
|
@@ -18,23 +18,8 @@ type VideoFrameEvent = {
|
|
|
18
18
|
timestampUs: bigint;
|
|
19
19
|
rotation: VideoRotation;
|
|
20
20
|
};
|
|
21
|
-
declare class VideoStream
|
|
22
|
-
/** @internal */
|
|
23
|
-
info?: VideoStreamInfo;
|
|
24
|
-
/** @internal */
|
|
25
|
-
ffiHandle: FfiHandle;
|
|
26
|
-
/** @internal */
|
|
27
|
-
eventQueue: (VideoFrameEvent | null)[];
|
|
28
|
-
/** @internal */
|
|
29
|
-
queueResolve: ((value: IteratorResult<VideoFrameEvent>) => void) | null;
|
|
30
|
-
/** @internal */
|
|
31
|
-
mutex: Mutex;
|
|
32
|
-
track: Track;
|
|
21
|
+
declare class VideoStream extends ReadableStream<VideoFrameEvent> {
|
|
33
22
|
constructor(track: Track);
|
|
34
|
-
private onEvent;
|
|
35
|
-
next(): Promise<IteratorResult<VideoFrameEvent>>;
|
|
36
|
-
close(): void;
|
|
37
|
-
[Symbol.asyncIterator](): VideoStream;
|
|
38
23
|
}
|
|
39
24
|
|
|
40
25
|
export { type VideoFrameEvent, VideoStream };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video_stream.d.ts","sourceRoot":"","sources":["../src/video_stream.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"video_stream.d.ts","sourceRoot":"","sources":["../src/video_stream.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAyB,MAAM,iBAAiB,CAAC;AAGxE,OAAO,KAAK,EAA0B,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;CACzB,CAAC;AAkEF,qBAAa,WAAY,SAAQ,cAAc,CAAC,eAAe,CAAC;gBAClD,KAAK,EAAE,KAAK;CAGzB"}
|
package/dist/video_stream.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReadableStream } from "node:stream/web";
|
|
2
2
|
import { FfiClient, FfiClientEvent, FfiHandle } from "./ffi_client.js";
|
|
3
3
|
import { NewVideoStreamRequest, VideoStreamType } from "./proto/video_frame_pb.js";
|
|
4
4
|
import { VideoFrame } from "./video_frame.js";
|
|
5
|
-
class
|
|
5
|
+
class VideoStreamSource {
|
|
6
6
|
constructor(track) {
|
|
7
|
-
/** @internal */
|
|
8
|
-
this.eventQueue = [];
|
|
9
|
-
/** @internal */
|
|
10
|
-
this.queueResolve = null;
|
|
11
|
-
/** @internal */
|
|
12
|
-
this.mutex = new Mutex();
|
|
13
7
|
this.onEvent = (ev) => {
|
|
8
|
+
if (!this.controller) {
|
|
9
|
+
throw new Error("Stream controller not initialized");
|
|
10
|
+
}
|
|
14
11
|
if (ev.message.case != "videoStreamEvent" || ev.message.value.streamHandle != this.ffiHandle.handle) {
|
|
15
12
|
return;
|
|
16
13
|
}
|
|
@@ -21,31 +18,19 @@ class VideoStream {
|
|
|
21
18
|
const timestampUs = streamEvent.value.timestampUs;
|
|
22
19
|
const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer);
|
|
23
20
|
const value = { rotation, timestampUs, frame };
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
rotation: value.rotation
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
this.queueResolve = null;
|
|
34
|
-
} else {
|
|
35
|
-
this.eventQueue.push({
|
|
36
|
-
frame: value.frame,
|
|
37
|
-
timestampUs: value.timestampUs,
|
|
38
|
-
rotation: value.rotation
|
|
39
|
-
});
|
|
40
|
-
}
|
|
21
|
+
const videoFrameEvent = {
|
|
22
|
+
frame: value.frame,
|
|
23
|
+
timestampUs: value.timestampUs,
|
|
24
|
+
rotation: value.rotation
|
|
25
|
+
};
|
|
26
|
+
this.controller.enqueue(videoFrameEvent);
|
|
41
27
|
break;
|
|
42
28
|
case "eos":
|
|
43
29
|
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
30
|
+
this.controller.close();
|
|
44
31
|
break;
|
|
45
32
|
}
|
|
46
33
|
};
|
|
47
|
-
var _a;
|
|
48
|
-
this.track = track;
|
|
49
34
|
const req = new NewVideoStreamRequest({
|
|
50
35
|
type: VideoStreamType.VIDEO_STREAM_NATIVE,
|
|
51
36
|
trackHandle: track.ffi_handle.handle
|
|
@@ -56,33 +41,20 @@ class VideoStream {
|
|
|
56
41
|
value: req
|
|
57
42
|
}
|
|
58
43
|
});
|
|
59
|
-
this.info = (_a = res.stream) == null ? void 0 : _a.info;
|
|
60
44
|
this.ffiHandle = new FfiHandle(res.stream.handle.id);
|
|
61
45
|
FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);
|
|
62
46
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (this.eventQueue.length > 0) {
|
|
66
|
-
unlock();
|
|
67
|
-
const value = this.eventQueue.shift();
|
|
68
|
-
if (value) {
|
|
69
|
-
return { done: false, value };
|
|
70
|
-
} else {
|
|
71
|
-
return { done: true, value: void 0 };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const promise = new Promise(
|
|
75
|
-
(resolve) => this.queueResolve = resolve
|
|
76
|
-
);
|
|
77
|
-
unlock();
|
|
78
|
-
return promise;
|
|
47
|
+
start(controller) {
|
|
48
|
+
this.controller = controller;
|
|
79
49
|
}
|
|
80
|
-
|
|
81
|
-
|
|
50
|
+
cancel() {
|
|
51
|
+
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
82
52
|
this.ffiHandle.dispose();
|
|
83
53
|
}
|
|
84
|
-
|
|
85
|
-
|
|
54
|
+
}
|
|
55
|
+
class VideoStream extends ReadableStream {
|
|
56
|
+
constructor(track) {
|
|
57
|
+
super(new VideoStreamSource(track));
|
|
86
58
|
}
|
|
87
59
|
}
|
|
88
60
|
export {
|
package/dist/video_stream.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/video_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { ReadableStream, type UnderlyingSource } from 'node:stream/web';\nimport type { FfiEvent } from './ffi_client.js';\nimport { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';\nimport type { NewVideoStreamResponse, VideoRotation } from './proto/video_frame_pb.js';\nimport { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js';\nimport type { Track } from './track.js';\nimport { VideoFrame } from './video_frame.js';\n\nexport type VideoFrameEvent = {\n frame: VideoFrame;\n timestampUs: bigint;\n rotation: VideoRotation;\n};\n\nclass VideoStreamSource implements UnderlyingSource<VideoFrameEvent> {\n private controller?: ReadableStreamDefaultController<VideoFrameEvent>;\n private ffiHandle: FfiHandle;\n\n constructor(track: Track) {\n const req = new NewVideoStreamRequest({\n type: VideoStreamType.VIDEO_STREAM_NATIVE,\n trackHandle: track.ffi_handle.handle,\n });\n\n const res = FfiClient.instance.request<NewVideoStreamResponse>({\n message: {\n case: 'newVideoStream',\n value: req,\n },\n });\n\n this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);\n FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);\n }\n\n private onEvent = (ev: FfiEvent) => {\n if (!this.controller) {\n throw new Error('Stream controller not initialized');\n }\n\n if (\n ev.message.case != 'videoStreamEvent' ||\n ev.message.value.streamHandle != this.ffiHandle.handle\n ) {\n return;\n }\n\n const streamEvent = ev.message.value.message;\n switch (streamEvent.case) {\n case 'frameReceived':\n const rotation = streamEvent.value.rotation;\n const timestampUs = streamEvent.value.timestampUs;\n const frame = VideoFrame.fromOwnedInfo(streamEvent.value.buffer!);\n const value = { rotation, timestampUs, frame };\n const videoFrameEvent = {\n frame: value.frame,\n timestampUs: value.timestampUs!,\n rotation: value.rotation!,\n };\n this.controller.enqueue(videoFrameEvent);\n break;\n case 'eos':\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.controller.close();\n break;\n }\n };\n\n start(controller: ReadableStreamDefaultController<VideoFrameEvent>) {\n this.controller = controller;\n }\n\n cancel() {\n FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);\n this.ffiHandle.dispose();\n }\n}\n\nexport class VideoStream extends ReadableStream<VideoFrameEvent> {\n constructor(track: Track) {\n super(new VideoStreamSource(track));\n }\n}\n"],"mappings":"AAGA,SAAS,sBAA6C;AAEtD,SAAS,WAAW,gBAAgB,iBAAiB;AAErD,SAAS,uBAAuB,uBAAuB;AAEvD,SAAS,kBAAkB;AAQ3B,MAAM,kBAA+D;AAAA,EAInE,YAAY,OAAc;AAiB1B,SAAQ,UAAU,CAAC,OAAiB;AAClC,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AAEA,UACE,GAAG,QAAQ,QAAQ,sBACnB,GAAG,QAAQ,MAAM,gBAAgB,KAAK,UAAU,QAChD;AACA;AAAA,MACF;AAEA,YAAM,cAAc,GAAG,QAAQ,MAAM;AACrC,cAAQ,YAAY,MAAM;AAAA,QACxB,KAAK;AACH,gBAAM,WAAW,YAAY,MAAM;AACnC,gBAAM,cAAc,YAAY,MAAM;AACtC,gBAAM,QAAQ,WAAW,cAAc,YAAY,MAAM,MAAO;AAChE,gBAAM,QAAQ,EAAE,UAAU,aAAa,MAAM;AAC7C,gBAAM,kBAAkB;AAAA,YACtB,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,UAAU,MAAM;AAAA,UAClB;AACA,eAAK,WAAW,QAAQ,eAAe;AACvC;AAAA,QACF,KAAK;AACH,oBAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,eAAK,WAAW,MAAM;AACtB;AAAA,MACJ;AAAA,IACF;AA/CE,UAAM,MAAM,IAAI,sBAAsB;AAAA,MACpC,MAAM,gBAAgB;AAAA,MACtB,aAAa,MAAM,WAAW;AAAA,IAChC,CAAC;AAED,UAAM,MAAM,UAAU,SAAS,QAAgC;AAAA,MAC7D,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,YAAY,IAAI,UAAU,IAAI,OAAQ,OAAQ,EAAG;AACtD,cAAU,SAAS,GAAG,eAAe,UAAU,KAAK,OAAO;AAAA,EAC7D;AAAA,EAmCA,MAAM,YAA8D;AAClE,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,SAAS;AACP,cAAU,SAAS,IAAI,eAAe,UAAU,KAAK,OAAO;AAC5D,SAAK,UAAU,QAAQ;AAAA,EACzB;AACF;AAEO,MAAM,oBAAoB,eAAgC;AAAA,EAC/D,YAAY,OAAc;AACxB,UAAM,IAAI,kBAAkB,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "LiveKit RTC Node",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "LiveKit",
|
|
6
|
-
"version": "0.13.
|
|
6
|
+
"version": "0.13.12",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"require": "dist/index.cjs",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"@bufbuild/protoc-gen-es": "^1.10.0"
|
|
62
62
|
},
|
|
63
63
|
"optionalDependencies": {
|
|
64
|
-
"@livekit/rtc-node-darwin-arm64": "0.13.
|
|
65
|
-
"@livekit/rtc-node-darwin-x64": "0.13.
|
|
66
|
-
"@livekit/rtc-node-linux-arm64-gnu": "0.13.
|
|
67
|
-
"@livekit/rtc-node-linux-x64-gnu": "0.13.
|
|
68
|
-
"@livekit/rtc-node-win32-x64-msvc": "0.13.
|
|
64
|
+
"@livekit/rtc-node-darwin-arm64": "0.13.12",
|
|
65
|
+
"@livekit/rtc-node-darwin-x64": "0.13.12",
|
|
66
|
+
"@livekit/rtc-node-linux-arm64-gnu": "0.13.12",
|
|
67
|
+
"@livekit/rtc-node-linux-x64-gnu": "0.13.12",
|
|
68
|
+
"@livekit/rtc-node-win32-x64-msvc": "0.13.12"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": ">= 18"
|
package/src/audio_filter.ts
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { FfiClient } from './ffi_client.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
LoadAudioFilterPluginResponse,
|
|
8
|
-
} from './proto/audio_frame_pb.js';
|
|
5
|
+
import type { LoadAudioFilterPluginResponse } from './proto/audio_frame_pb.js';
|
|
6
|
+
import { LoadAudioFilterPluginRequest } from './proto/audio_frame_pb.js';
|
|
9
7
|
|
|
10
8
|
export class AudioFilter {
|
|
11
9
|
constructor(moduleId: string, path: string, dependencies: string[] = []) {
|
package/src/audio_source.ts
CHANGED
|
@@ -99,6 +99,7 @@ export class AudioSource {
|
|
|
99
99
|
this.lastCapture = 0;
|
|
100
100
|
this.currentQueueSize = 0;
|
|
101
101
|
this.promise = this.newPromise();
|
|
102
|
+
this.timeout = undefined;
|
|
102
103
|
});
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -106,6 +107,11 @@ export class AudioSource {
|
|
|
106
107
|
if (this.closed) {
|
|
107
108
|
throw new Error('AudioSource is closed');
|
|
108
109
|
}
|
|
110
|
+
|
|
111
|
+
if (frame.samplesPerChannel === 0) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
109
115
|
const now = Number(process.hrtime.bigint() / BigInt(1000000));
|
|
110
116
|
const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
|
|
111
117
|
const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;
|
|
@@ -117,9 +123,7 @@ export class AudioSource {
|
|
|
117
123
|
clearTimeout(this.timeout);
|
|
118
124
|
}
|
|
119
125
|
|
|
120
|
-
|
|
121
|
-
// (e.g. using wait_for_playout for very small chunks)
|
|
122
|
-
this.timeout = setTimeout(this.release, this.currentQueueSize - 50);
|
|
126
|
+
this.timeout = setTimeout(this.release, this.currentQueueSize);
|
|
123
127
|
|
|
124
128
|
const req = new CaptureAudioFrameRequest({
|
|
125
129
|
sourceHandle: this.ffiHandle.handle,
|
package/src/audio_stream.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import {
|
|
4
|
+
import { ReadableStream, type UnderlyingSource } from 'node:stream/web';
|
|
5
5
|
import { AudioFrame } from './audio_frame.js';
|
|
6
6
|
import type { FfiEvent } from './ffi_client.js';
|
|
7
7
|
import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { NewAudioStreamResponse } from './proto/audio_frame_pb.js';
|
|
9
9
|
import { AudioStreamType, NewAudioStreamRequest } from './proto/audio_frame_pb.js';
|
|
10
10
|
import type { Track } from './track.js';
|
|
11
11
|
|
|
@@ -20,34 +20,18 @@ export interface NoiseCancellationOptions {
|
|
|
20
20
|
options: Record<string, any>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
eventQueue: (AudioFrame | null)[] = [];
|
|
30
|
-
/** @internal */
|
|
31
|
-
queueResolve: ((value: IteratorResult<AudioFrame>) => void) | null = null;
|
|
32
|
-
/** @internal */
|
|
33
|
-
mutex = new Mutex();
|
|
34
|
-
|
|
35
|
-
track: Track;
|
|
36
|
-
sampleRate: number;
|
|
37
|
-
numChannels: number;
|
|
38
|
-
ncOptions?: NoiseCancellationOptions;
|
|
39
|
-
|
|
40
|
-
constructor(track: Track);
|
|
41
|
-
constructor(track: Track, sampleRate: number);
|
|
42
|
-
constructor(track: Track, sampleRate: number, numChannels: number);
|
|
43
|
-
constructor(track: Track, options: AudioStreamOptions);
|
|
23
|
+
class AudioStreamSource implements UnderlyingSource<AudioFrame> {
|
|
24
|
+
private controller?: ReadableStreamDefaultController<AudioFrame>;
|
|
25
|
+
private ffiHandle: FfiHandle;
|
|
26
|
+
private sampleRate: number;
|
|
27
|
+
private numChannels: number;
|
|
28
|
+
private ncOptions?: NoiseCancellationOptions;
|
|
44
29
|
|
|
45
30
|
constructor(
|
|
46
31
|
track: Track,
|
|
47
32
|
sampleRateOrOptions?: number | AudioStreamOptions,
|
|
48
33
|
numChannels?: number,
|
|
49
34
|
) {
|
|
50
|
-
this.track = track;
|
|
51
35
|
if (sampleRateOrOptions !== undefined && typeof sampleRateOrOptions !== 'number') {
|
|
52
36
|
this.sampleRate = sampleRateOrOptions.sampleRate ?? 48000;
|
|
53
37
|
this.numChannels = sampleRateOrOptions.numChannels ?? 1;
|
|
@@ -77,13 +61,16 @@ export class AudioStream implements AsyncIterableIterator<AudioFrame> {
|
|
|
77
61
|
},
|
|
78
62
|
});
|
|
79
63
|
|
|
80
|
-
this.info = res.stream!.info!;
|
|
81
64
|
this.ffiHandle = new FfiHandle(res.stream!.handle!.id!);
|
|
82
65
|
|
|
83
66
|
FfiClient.instance.on(FfiClientEvent.FfiEvent, this.onEvent);
|
|
84
67
|
}
|
|
85
68
|
|
|
86
69
|
private onEvent = (ev: FfiEvent) => {
|
|
70
|
+
if (!this.controller) {
|
|
71
|
+
throw new Error('Stream controller not initialized');
|
|
72
|
+
}
|
|
73
|
+
|
|
87
74
|
if (
|
|
88
75
|
ev.message.case != 'audioStreamEvent' ||
|
|
89
76
|
ev.message.value.streamHandle != this.ffiHandle.handle
|
|
@@ -95,43 +82,35 @@ export class AudioStream implements AsyncIterableIterator<AudioFrame> {
|
|
|
95
82
|
switch (streamEvent.case) {
|
|
96
83
|
case 'frameReceived':
|
|
97
84
|
const frame = AudioFrame.fromOwnedInfo(streamEvent.value.frame!);
|
|
98
|
-
|
|
99
|
-
this.queueResolve({ done: false, value: frame });
|
|
100
|
-
this.queueResolve = null;
|
|
101
|
-
} else {
|
|
102
|
-
this.eventQueue.push(frame);
|
|
103
|
-
}
|
|
85
|
+
this.controller.enqueue(frame);
|
|
104
86
|
break;
|
|
105
87
|
case 'eos':
|
|
106
88
|
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
89
|
+
this.controller.close();
|
|
107
90
|
break;
|
|
108
91
|
}
|
|
109
92
|
};
|
|
110
93
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (this.eventQueue.length > 0) {
|
|
114
|
-
unlock();
|
|
115
|
-
const value = this.eventQueue.shift();
|
|
116
|
-
if (value) {
|
|
117
|
-
return { done: false, value };
|
|
118
|
-
} else {
|
|
119
|
-
return { done: true, value: undefined };
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const promise = new Promise<IteratorResult<AudioFrame>>(
|
|
123
|
-
(resolve) => (this.queueResolve = resolve),
|
|
124
|
-
);
|
|
125
|
-
unlock();
|
|
126
|
-
return promise;
|
|
94
|
+
start(controller: ReadableStreamDefaultController<AudioFrame>) {
|
|
95
|
+
this.controller = controller;
|
|
127
96
|
}
|
|
128
97
|
|
|
129
|
-
|
|
130
|
-
|
|
98
|
+
cancel() {
|
|
99
|
+
FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
|
|
131
100
|
this.ffiHandle.dispose();
|
|
132
101
|
}
|
|
102
|
+
}
|
|
133
103
|
|
|
134
|
-
|
|
135
|
-
|
|
104
|
+
export class AudioStream extends ReadableStream<AudioFrame> {
|
|
105
|
+
constructor(track: Track);
|
|
106
|
+
constructor(track: Track, sampleRate: number);
|
|
107
|
+
constructor(track: Track, sampleRate: number, numChannels: number);
|
|
108
|
+
constructor(track: Track, options: AudioStreamOptions);
|
|
109
|
+
constructor(
|
|
110
|
+
track: Track,
|
|
111
|
+
sampleRateOrOptions?: number | AudioStreamOptions,
|
|
112
|
+
numChannels?: number,
|
|
113
|
+
) {
|
|
114
|
+
super(new AudioStreamSource(track, sampleRateOrOptions, numChannels));
|
|
136
115
|
}
|
|
137
116
|
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.13.
|
|
1
|
+
export const SDK_VERSION = "0.13.12";
|