@livekit/rtc-node 0.13.18 → 0.13.20
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_frame.d.ts.map +1 -1
- package/dist/audio_source.cjs +2 -1
- package/dist/audio_source.cjs.map +1 -1
- package/dist/audio_source.d.ts.map +1 -1
- package/dist/audio_source.js +2 -1
- package/dist/audio_source.js.map +1 -1
- package/dist/data_streams/stream_reader.cjs +2 -2
- package/dist/data_streams/stream_reader.cjs.map +1 -1
- package/dist/data_streams/stream_reader.js +2 -2
- package/dist/data_streams/stream_reader.js.map +1 -1
- package/dist/proto/audio_frame_pb.cjs.map +1 -1
- package/dist/proto/audio_frame_pb.js.map +1 -1
- package/dist/proto/data_stream_pb.cjs.map +1 -1
- package/dist/proto/data_stream_pb.js.map +1 -1
- package/dist/proto/e2ee_pb.cjs.map +1 -1
- package/dist/proto/e2ee_pb.js.map +1 -1
- package/dist/proto/ffi_pb.cjs.map +1 -1
- package/dist/proto/ffi_pb.js.map +1 -1
- package/dist/proto/handle_pb.cjs.map +1 -1
- package/dist/proto/handle_pb.js.map +1 -1
- package/dist/proto/participant_pb.cjs.map +1 -1
- package/dist/proto/participant_pb.js.map +1 -1
- package/dist/proto/room_pb.cjs.map +1 -1
- package/dist/proto/room_pb.js.map +1 -1
- package/dist/proto/rpc_pb.cjs.map +1 -1
- package/dist/proto/rpc_pb.js.map +1 -1
- package/dist/proto/stats_pb.cjs.map +1 -1
- package/dist/proto/stats_pb.js.map +1 -1
- package/dist/proto/track_pb.cjs.map +1 -1
- package/dist/proto/track_pb.js.map +1 -1
- package/dist/proto/track_publication_pb.cjs.map +1 -1
- package/dist/proto/track_publication_pb.js.map +1 -1
- package/dist/proto/video_frame_pb.cjs.map +1 -1
- package/dist/proto/video_frame_pb.js.map +1 -1
- package/dist/room.cjs +11 -2
- package/dist/room.cjs.map +1 -1
- package/dist/room.d.ts.map +1 -1
- package/dist/room.js +11 -2
- package/dist/room.js.map +1 -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/package.json +9 -9
- package/src/audio_source.ts +2 -1
- package/src/data_streams/stream_reader.ts +4 -4
- package/src/proto/audio_frame_pb.ts +1 -1
- package/src/proto/data_stream_pb.ts +1 -1
- package/src/proto/e2ee_pb.ts +1 -1
- package/src/proto/ffi_pb.ts +1 -1
- package/src/proto/handle_pb.ts +1 -1
- package/src/proto/participant_pb.ts +1 -1
- package/src/proto/room_pb.ts +1 -1
- package/src/proto/rpc_pb.ts +1 -1
- package/src/proto/stats_pb.ts +1 -1
- package/src/proto/track_pb.ts +1 -1
- package/src/proto/track_publication_pb.ts +1 -1
- package/src/proto/video_frame_pb.ts +1 -1
- package/src/room.ts +11 -2
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio_frame.d.ts","sourceRoot":"","sources":["../src/audio_frame.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,qBAAa,UAAU;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;gBAOd,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM;IAO7F,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,UAAU;IAK1F,gBAAgB;IAChB,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,qBAAqB,GAAG,UAAU;IAa9D,gBAAgB;IAChB,SAAS,IAAI,oBAAoB;CAQlC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"audio_frame.d.ts","sourceRoot":"","sources":["../src/audio_frame.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,qBAAa,UAAU;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;gBAOd,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM;IAO7F,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,UAAU;IAK1F,gBAAgB;IAChB,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,qBAAqB,GAAG,UAAU;IAa9D,gBAAgB;IAChB,SAAS,IAAI,oBAAoB;CAQlC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,UAAU,GAAG,UAAU,EAAE,KAAG,UA4BtE,CAAC"}
|
package/dist/audio_source.cjs
CHANGED
|
@@ -70,6 +70,7 @@ class AudioSource {
|
|
|
70
70
|
value: req
|
|
71
71
|
}
|
|
72
72
|
});
|
|
73
|
+
this.currentQueueSize = 0;
|
|
73
74
|
this.release();
|
|
74
75
|
}
|
|
75
76
|
/** @internal */
|
|
@@ -96,7 +97,7 @@ class AudioSource {
|
|
|
96
97
|
const now = Number(process.hrtime.bigint() / BigInt(1e6));
|
|
97
98
|
const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
|
|
98
99
|
const frameDurationMs = frame.samplesPerChannel / frame.sampleRate * 1e3;
|
|
99
|
-
this.currentQueueSize
|
|
100
|
+
this.currentQueueSize = Math.max(this.currentQueueSize - elapsed, 0) + frameDurationMs;
|
|
100
101
|
this.lastCapture = now;
|
|
101
102
|
if (this.timeout) {
|
|
102
103
|
clearTimeout(this.timeout);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/audio_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from './audio_frame.js';\nimport { FfiClient } from './ffi_client.js';\nimport { FfiHandle } from './napi/native.js';\nimport type {\n AudioSourceInfo,\n CaptureAudioFrameCallback,\n CaptureAudioFrameResponse,\n ClearAudioBufferResponse,\n NewAudioSourceResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n AudioSourceType,\n CaptureAudioFrameRequest,\n ClearAudioBufferRequest,\n NewAudioSourceRequest,\n} from './proto/audio_frame_pb.js';\n\nexport class AudioSource {\n /** @internal */\n info: AudioSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n lastCapture: number;\n /** @internal */\n currentQueueSize: number;\n /** @internal */\n release = () => {};\n promise = this.newPromise();\n /** @internal */\n timeout?: ReturnType<typeof setTimeout> = undefined;\n /** @internal */\n closed = false;\n\n sampleRate: number;\n numChannels: number;\n queueSize: number;\n\n constructor(sampleRate: number, numChannels: number, queueSize = 1000) {\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.queueSize = queueSize;\n\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n\n const req = new NewAudioSourceRequest({\n type: AudioSourceType.AUDIO_SOURCE_NATIVE,\n sampleRate: sampleRate,\n numChannels: numChannels,\n queueSizeMs: queueSize,\n });\n\n const res = FfiClient.instance.request<NewAudioSourceResponse>({\n message: {\n case: 'newAudioSource',\n value: req,\n },\n });\n\n this.info = res.source!.info!;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n get queuedDuration(): number {\n return Math.max(\n this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1000000)) + this.lastCapture,\n 0,\n );\n }\n\n clearQueue() {\n const req = new ClearAudioBufferRequest({\n sourceHandle: this.ffiHandle.handle,\n });\n\n FfiClient.instance.request<ClearAudioBufferResponse>({\n message: {\n case: 'clearAudioBuffer',\n value: req,\n },\n });\n\n this.release();\n }\n\n /** @internal */\n async newPromise() {\n return new Promise<void>((resolve) => {\n this.release = resolve;\n });\n }\n\n async waitForPlayout() {\n return this.promise.then(() => {\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n this.promise = this.newPromise();\n this.timeout = undefined;\n });\n }\n\n async captureFrame(frame: AudioFrame) {\n if (this.closed) {\n throw new Error('AudioSource is closed');\n }\n\n if (frame.samplesPerChannel === 0) {\n return;\n }\n\n const now = Number(process.hrtime.bigint() / BigInt(1000000));\n const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;\n const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;\n this.currentQueueSize
|
|
1
|
+
{"version":3,"sources":["../src/audio_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from './audio_frame.js';\nimport { FfiClient } from './ffi_client.js';\nimport { FfiHandle } from './napi/native.js';\nimport type {\n AudioSourceInfo,\n CaptureAudioFrameCallback,\n CaptureAudioFrameResponse,\n ClearAudioBufferResponse,\n NewAudioSourceResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n AudioSourceType,\n CaptureAudioFrameRequest,\n ClearAudioBufferRequest,\n NewAudioSourceRequest,\n} from './proto/audio_frame_pb.js';\n\nexport class AudioSource {\n /** @internal */\n info: AudioSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n lastCapture: number;\n /** @internal */\n currentQueueSize: number;\n /** @internal */\n release = () => {};\n promise = this.newPromise();\n /** @internal */\n timeout?: ReturnType<typeof setTimeout> = undefined;\n /** @internal */\n closed = false;\n\n sampleRate: number;\n numChannels: number;\n queueSize: number;\n\n constructor(sampleRate: number, numChannels: number, queueSize = 1000) {\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.queueSize = queueSize;\n\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n\n const req = new NewAudioSourceRequest({\n type: AudioSourceType.AUDIO_SOURCE_NATIVE,\n sampleRate: sampleRate,\n numChannels: numChannels,\n queueSizeMs: queueSize,\n });\n\n const res = FfiClient.instance.request<NewAudioSourceResponse>({\n message: {\n case: 'newAudioSource',\n value: req,\n },\n });\n\n this.info = res.source!.info!;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n get queuedDuration(): number {\n return Math.max(\n this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1000000)) + this.lastCapture,\n 0,\n );\n }\n\n clearQueue() {\n const req = new ClearAudioBufferRequest({\n sourceHandle: this.ffiHandle.handle,\n });\n\n FfiClient.instance.request<ClearAudioBufferResponse>({\n message: {\n case: 'clearAudioBuffer',\n value: req,\n },\n });\n\n this.currentQueueSize = 0;\n this.release();\n }\n\n /** @internal */\n async newPromise() {\n return new Promise<void>((resolve) => {\n this.release = resolve;\n });\n }\n\n async waitForPlayout() {\n return this.promise.then(() => {\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n this.promise = this.newPromise();\n this.timeout = undefined;\n });\n }\n\n async captureFrame(frame: AudioFrame) {\n if (this.closed) {\n throw new Error('AudioSource is closed');\n }\n\n if (frame.samplesPerChannel === 0) {\n return;\n }\n\n const now = Number(process.hrtime.bigint() / BigInt(1000000));\n const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;\n const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;\n this.currentQueueSize = Math.max(this.currentQueueSize - elapsed, 0) + frameDurationMs;\n\n this.lastCapture = now;\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n\n this.timeout = setTimeout(this.release, this.currentQueueSize);\n\n const req = new CaptureAudioFrameRequest({\n sourceHandle: this.ffiHandle.handle,\n buffer: frame.protoInfo(),\n });\n\n const res = FfiClient.instance.request<CaptureAudioFrameResponse>({\n message: { case: 'captureAudioFrame', value: req },\n });\n\n const cb = await FfiClient.instance.waitFor<CaptureAudioFrameCallback>((ev) => {\n return ev.message.case == 'captureAudioFrame' && ev.message.value.asyncId == res.asyncId;\n });\n\n if (cb.error) {\n throw new Error(cb.error);\n }\n }\n\n async close() {\n this.ffiHandle.dispose();\n this.closed = true;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio_source.d.ts","sourceRoot":"","sources":["../src/audio_source.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,2BAA2B,CAAC;AAQnC,qBAAa,WAAW;IACtB,gBAAgB;IAChB,IAAI,EAAE,eAAe,CAAC;IACtB,gBAAgB;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB;IAChB,OAAO,aAAY;IACnB,OAAO,gBAAqB;IAC5B,gBAAgB;IAChB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAa;IACpD,gBAAgB;IAChB,MAAM,UAAS;IAEf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;gBAEN,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,SAAO;IA0BrE,IAAI,cAAc,IAAI,MAAM,CAK3B;IAED,UAAU;
|
|
1
|
+
{"version":3,"file":"audio_source.d.ts","sourceRoot":"","sources":["../src/audio_source.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,2BAA2B,CAAC;AAQnC,qBAAa,WAAW;IACtB,gBAAgB;IAChB,IAAI,EAAE,eAAe,CAAC;IACtB,gBAAgB;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB;IAChB,OAAO,aAAY;IACnB,OAAO,gBAAqB;IAC5B,gBAAgB;IAChB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAa;IACpD,gBAAgB;IAChB,MAAM,UAAS;IAEf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;gBAEN,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,SAAO;IA0BrE,IAAI,cAAc,IAAI,MAAM,CAK3B;IAED,UAAU;IAgBV,gBAAgB;IACV,UAAU;IAMV,cAAc;IASd,YAAY,CAAC,KAAK,EAAE,UAAU;IAwC9B,KAAK;CAIZ"}
|
package/dist/audio_source.js
CHANGED
|
@@ -52,6 +52,7 @@ class AudioSource {
|
|
|
52
52
|
value: req
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
|
+
this.currentQueueSize = 0;
|
|
55
56
|
this.release();
|
|
56
57
|
}
|
|
57
58
|
/** @internal */
|
|
@@ -78,7 +79,7 @@ class AudioSource {
|
|
|
78
79
|
const now = Number(process.hrtime.bigint() / BigInt(1e6));
|
|
79
80
|
const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;
|
|
80
81
|
const frameDurationMs = frame.samplesPerChannel / frame.sampleRate * 1e3;
|
|
81
|
-
this.currentQueueSize
|
|
82
|
+
this.currentQueueSize = Math.max(this.currentQueueSize - elapsed, 0) + frameDurationMs;
|
|
82
83
|
this.lastCapture = now;
|
|
83
84
|
if (this.timeout) {
|
|
84
85
|
clearTimeout(this.timeout);
|
package/dist/audio_source.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/audio_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from './audio_frame.js';\nimport { FfiClient } from './ffi_client.js';\nimport { FfiHandle } from './napi/native.js';\nimport type {\n AudioSourceInfo,\n CaptureAudioFrameCallback,\n CaptureAudioFrameResponse,\n ClearAudioBufferResponse,\n NewAudioSourceResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n AudioSourceType,\n CaptureAudioFrameRequest,\n ClearAudioBufferRequest,\n NewAudioSourceRequest,\n} from './proto/audio_frame_pb.js';\n\nexport class AudioSource {\n /** @internal */\n info: AudioSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n lastCapture: number;\n /** @internal */\n currentQueueSize: number;\n /** @internal */\n release = () => {};\n promise = this.newPromise();\n /** @internal */\n timeout?: ReturnType<typeof setTimeout> = undefined;\n /** @internal */\n closed = false;\n\n sampleRate: number;\n numChannels: number;\n queueSize: number;\n\n constructor(sampleRate: number, numChannels: number, queueSize = 1000) {\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.queueSize = queueSize;\n\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n\n const req = new NewAudioSourceRequest({\n type: AudioSourceType.AUDIO_SOURCE_NATIVE,\n sampleRate: sampleRate,\n numChannels: numChannels,\n queueSizeMs: queueSize,\n });\n\n const res = FfiClient.instance.request<NewAudioSourceResponse>({\n message: {\n case: 'newAudioSource',\n value: req,\n },\n });\n\n this.info = res.source!.info!;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n get queuedDuration(): number {\n return Math.max(\n this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1000000)) + this.lastCapture,\n 0,\n );\n }\n\n clearQueue() {\n const req = new ClearAudioBufferRequest({\n sourceHandle: this.ffiHandle.handle,\n });\n\n FfiClient.instance.request<ClearAudioBufferResponse>({\n message: {\n case: 'clearAudioBuffer',\n value: req,\n },\n });\n\n this.release();\n }\n\n /** @internal */\n async newPromise() {\n return new Promise<void>((resolve) => {\n this.release = resolve;\n });\n }\n\n async waitForPlayout() {\n return this.promise.then(() => {\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n this.promise = this.newPromise();\n this.timeout = undefined;\n });\n }\n\n async captureFrame(frame: AudioFrame) {\n if (this.closed) {\n throw new Error('AudioSource is closed');\n }\n\n if (frame.samplesPerChannel === 0) {\n return;\n }\n\n const now = Number(process.hrtime.bigint() / BigInt(1000000));\n const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;\n const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;\n this.currentQueueSize
|
|
1
|
+
{"version":3,"sources":["../src/audio_source.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from './audio_frame.js';\nimport { FfiClient } from './ffi_client.js';\nimport { FfiHandle } from './napi/native.js';\nimport type {\n AudioSourceInfo,\n CaptureAudioFrameCallback,\n CaptureAudioFrameResponse,\n ClearAudioBufferResponse,\n NewAudioSourceResponse,\n} from './proto/audio_frame_pb.js';\nimport {\n AudioSourceType,\n CaptureAudioFrameRequest,\n ClearAudioBufferRequest,\n NewAudioSourceRequest,\n} from './proto/audio_frame_pb.js';\n\nexport class AudioSource {\n /** @internal */\n info: AudioSourceInfo;\n /** @internal */\n ffiHandle: FfiHandle;\n /** @internal */\n lastCapture: number;\n /** @internal */\n currentQueueSize: number;\n /** @internal */\n release = () => {};\n promise = this.newPromise();\n /** @internal */\n timeout?: ReturnType<typeof setTimeout> = undefined;\n /** @internal */\n closed = false;\n\n sampleRate: number;\n numChannels: number;\n queueSize: number;\n\n constructor(sampleRate: number, numChannels: number, queueSize = 1000) {\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.queueSize = queueSize;\n\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n\n const req = new NewAudioSourceRequest({\n type: AudioSourceType.AUDIO_SOURCE_NATIVE,\n sampleRate: sampleRate,\n numChannels: numChannels,\n queueSizeMs: queueSize,\n });\n\n const res = FfiClient.instance.request<NewAudioSourceResponse>({\n message: {\n case: 'newAudioSource',\n value: req,\n },\n });\n\n this.info = res.source!.info!;\n this.ffiHandle = new FfiHandle(res.source!.handle!.id!);\n }\n\n get queuedDuration(): number {\n return Math.max(\n this.currentQueueSize - Number(process.hrtime.bigint() / BigInt(1000000)) + this.lastCapture,\n 0,\n );\n }\n\n clearQueue() {\n const req = new ClearAudioBufferRequest({\n sourceHandle: this.ffiHandle.handle,\n });\n\n FfiClient.instance.request<ClearAudioBufferResponse>({\n message: {\n case: 'clearAudioBuffer',\n value: req,\n },\n });\n\n this.currentQueueSize = 0;\n this.release();\n }\n\n /** @internal */\n async newPromise() {\n return new Promise<void>((resolve) => {\n this.release = resolve;\n });\n }\n\n async waitForPlayout() {\n return this.promise.then(() => {\n this.lastCapture = 0;\n this.currentQueueSize = 0;\n this.promise = this.newPromise();\n this.timeout = undefined;\n });\n }\n\n async captureFrame(frame: AudioFrame) {\n if (this.closed) {\n throw new Error('AudioSource is closed');\n }\n\n if (frame.samplesPerChannel === 0) {\n return;\n }\n\n const now = Number(process.hrtime.bigint() / BigInt(1000000));\n const elapsed = this.lastCapture === 0 ? 0 : now - this.lastCapture;\n const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;\n this.currentQueueSize = Math.max(this.currentQueueSize - elapsed, 0) + frameDurationMs;\n\n this.lastCapture = now;\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n\n this.timeout = setTimeout(this.release, this.currentQueueSize);\n\n const req = new CaptureAudioFrameRequest({\n sourceHandle: this.ffiHandle.handle,\n buffer: frame.protoInfo(),\n });\n\n const res = FfiClient.instance.request<CaptureAudioFrameResponse>({\n message: { case: 'captureAudioFrame', value: req },\n });\n\n const cb = await FfiClient.instance.waitFor<CaptureAudioFrameCallback>((ev) => {\n return ev.message.case == 'captureAudioFrame' && ev.message.value.asyncId == res.asyncId;\n });\n\n if (cb.error) {\n throw new Error(cb.error);\n }\n }\n\n async close() {\n this.ffiHandle.dispose();\n this.closed = true;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -55,7 +55,7 @@ class ByteStreamReader extends BaseStreamReader {
|
|
|
55
55
|
return { done: false, value: value.content };
|
|
56
56
|
}
|
|
57
57
|
} catch (error) {
|
|
58
|
-
import_log.log.error("error processing stream update", error);
|
|
58
|
+
import_log.log.error("error processing stream update: %s", error);
|
|
59
59
|
return { done: true, value: void 0 };
|
|
60
60
|
}
|
|
61
61
|
},
|
|
@@ -115,7 +115,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
} catch (error) {
|
|
118
|
-
import_log.log.error("error processing stream update", error);
|
|
118
|
+
import_log.log.error("error processing stream update: %s", error);
|
|
119
119
|
return { done: true, value: void 0 };
|
|
120
120
|
}
|
|
121
121
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data_streams/stream_reader.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '../log.js';\nimport type { DataStream_Chunk } from '../proto/room_pb.js';\nimport { bigIntToNumber } from '../utils.js';\nimport type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';\n\nabstract class BaseStreamReader<T extends BaseStreamInfo> {\n protected reader: ReadableStream<DataStream_Chunk>;\n\n protected totalByteSize?: number;\n\n protected _info: T;\n\n protected bytesReceived: number;\n\n get info() {\n return this._info;\n }\n\n constructor(info: T, stream: ReadableStream<DataStream_Chunk>, totalByteSize?: number) {\n this.reader = stream;\n this.totalByteSize = totalByteSize;\n this._info = info;\n this.bytesReceived = 0;\n }\n\n protected abstract handleChunkReceived(chunk: DataStream_Chunk): void;\n\n onProgress?: (progress: number | undefined) => void;\n\n abstract readAll(): Promise<string | Array<Uint8Array>>;\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n this.bytesReceived += chunk.content!.byteLength;\n const currentProgress = this.totalByteSize\n ? this.bytesReceived / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n\n return {\n next: async (): Promise<IteratorResult<Uint8Array>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined as any };\n } else {\n this.handleChunkReceived(value);\n return { done: false, value: value.content! };\n }\n } catch (error) {\n log.error('error processing stream update', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<Uint8Array> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<Array<Uint8Array>> {\n const chunks: Set<Uint8Array> = new Set();\n for await (const chunk of this) {\n chunks.add(chunk);\n }\n return Array.from(chunks);\n }\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class TextStreamReader extends BaseStreamReader<TextStreamInfo> {\n private receivedChunks: Map<number, DataStream_Chunk>;\n\n /**\n * A TextStreamReader instance can be used as an AsyncIterator that returns the entire string\n * that has been received up to the current point in time.\n */\n constructor(\n info: TextStreamInfo,\n stream: ReadableStream<DataStream_Chunk>,\n totalChunkCount?: number,\n ) {\n super(info, stream, totalChunkCount);\n this.receivedChunks = new Map();\n }\n\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n const index = bigIntToNumber(chunk.chunkIndex!);\n const previousChunkAtIndex = this.receivedChunks.get(index!);\n if (previousChunkAtIndex && previousChunkAtIndex.version! > chunk.version!) {\n // we have a newer version already, dropping the old one\n return;\n }\n this.receivedChunks.set(index, chunk);\n const currentProgress = this.totalByteSize\n ? this.receivedChunks.size / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n /**\n * Async iterator implementation to allow usage of `for await...of` syntax.\n * Yields structured chunks from the stream.\n *\n */\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n const decoder = new TextDecoder();\n\n return {\n next: async (): Promise<IteratorResult<string>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined };\n } else {\n this.handleChunkReceived(value);\n return {\n done: false,\n value: decoder.decode(value.content!),\n };\n }\n } catch (error) {\n log.error('error processing stream update', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<string> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<string> {\n let finalString: string = '';\n for await (const chunk of this) {\n finalString += chunk;\n }\n return finalString;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBAAoB;AAEpB,mBAA+B;AAG/B,MAAe,iBAA2C;AAAA,EASxD,IAAI,OAAO;AACT,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAY,MAAS,QAA0C,eAAwB;AACrF,SAAK,SAAS;AACd,SAAK,gBAAgB;AACrB,SAAK,QAAQ;AACb,SAAK,gBAAgB;AAAA,EACvB;AAOF;AAKO,MAAM,yBAAyB,iBAAiC;AAAA,EAC3D,oBAAoB,OAAyB;AAvCzD;AAwCI,SAAK,iBAAiB,MAAM,QAAS;AACrC,UAAM,kBAAkB,KAAK,gBACzB,KAAK,gBAAgB,KAAK,gBAC1B;AACJ,eAAK,eAAL,8BAAkB;AAAA,EACpB;AAAA,EAEA,CAAC,OAAO,aAAa,IAAI;AACvB,UAAM,SAAS,KAAK,OAAO,UAAU;AAErC,WAAO;AAAA,MACL,MAAM,YAAiD;AACrD,YAAI;AACF,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,cAAI,MAAM;AACR,mBAAO,EAAE,MAAM,MAAM,OAAO,OAAiB;AAAA,UAC/C,OAAO;AACL,iBAAK,oBAAoB,KAAK;AAC9B,mBAAO,EAAE,MAAM,OAAO,OAAO,MAAM,QAAS;AAAA,UAC9C;AAAA,QACF,SAAS,
|
|
1
|
+
{"version":3,"sources":["../../src/data_streams/stream_reader.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '../log.js';\nimport type { DataStream_Chunk } from '../proto/room_pb.js';\nimport { bigIntToNumber } from '../utils.js';\nimport type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';\n\nabstract class BaseStreamReader<T extends BaseStreamInfo> {\n protected reader: ReadableStream<DataStream_Chunk>;\n\n protected totalByteSize?: number;\n\n protected _info: T;\n\n protected bytesReceived: number;\n\n get info() {\n return this._info;\n }\n\n constructor(info: T, stream: ReadableStream<DataStream_Chunk>, totalByteSize?: number) {\n this.reader = stream;\n this.totalByteSize = totalByteSize;\n this._info = info;\n this.bytesReceived = 0;\n }\n\n protected abstract handleChunkReceived(chunk: DataStream_Chunk): void;\n\n onProgress?: (progress: number | undefined) => void;\n\n abstract readAll(): Promise<string | Array<Uint8Array>>;\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n this.bytesReceived += chunk.content!.byteLength;\n const currentProgress = this.totalByteSize\n ? this.bytesReceived / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n\n return {\n next: async (): Promise<IteratorResult<Uint8Array>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined as any };\n } else {\n this.handleChunkReceived(value);\n return { done: false, value: value.content! };\n }\n } catch (error: any) {\n log.error('error processing stream update: %s', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<Uint8Array> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<Array<Uint8Array>> {\n const chunks: Set<Uint8Array> = new Set();\n for await (const chunk of this) {\n chunks.add(chunk);\n }\n return Array.from(chunks);\n }\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class TextStreamReader extends BaseStreamReader<TextStreamInfo> {\n private receivedChunks: Map<number, DataStream_Chunk>;\n\n /**\n * A TextStreamReader instance can be used as an AsyncIterator that returns the entire string\n * that has been received up to the current point in time.\n */\n constructor(\n info: TextStreamInfo,\n stream: ReadableStream<DataStream_Chunk>,\n totalChunkCount?: number,\n ) {\n super(info, stream, totalChunkCount);\n this.receivedChunks = new Map();\n }\n\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n const index = bigIntToNumber(chunk.chunkIndex!);\n const previousChunkAtIndex = this.receivedChunks.get(index!);\n if (previousChunkAtIndex && previousChunkAtIndex.version! > chunk.version!) {\n // we have a newer version already, dropping the old one\n return;\n }\n this.receivedChunks.set(index, chunk);\n const currentProgress = this.totalByteSize\n ? this.receivedChunks.size / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n /**\n * Async iterator implementation to allow usage of `for await...of` syntax.\n * Yields structured chunks from the stream.\n *\n */\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n const decoder = new TextDecoder();\n\n return {\n next: async (): Promise<IteratorResult<string>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined };\n } else {\n this.handleChunkReceived(value);\n return {\n done: false,\n value: decoder.decode(value.content!),\n };\n }\n } catch (error: any) {\n log.error('error processing stream update: %s', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<string> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<string> {\n let finalString: string = '';\n for await (const chunk of this) {\n finalString += chunk;\n }\n return finalString;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -31,7 +31,7 @@ class ByteStreamReader extends BaseStreamReader {
|
|
|
31
31
|
return { done: false, value: value.content };
|
|
32
32
|
}
|
|
33
33
|
} catch (error) {
|
|
34
|
-
log.error("error processing stream update", error);
|
|
34
|
+
log.error("error processing stream update: %s", error);
|
|
35
35
|
return { done: true, value: void 0 };
|
|
36
36
|
}
|
|
37
37
|
},
|
|
@@ -91,7 +91,7 @@ class TextStreamReader extends BaseStreamReader {
|
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
} catch (error) {
|
|
94
|
-
log.error("error processing stream update", error);
|
|
94
|
+
log.error("error processing stream update: %s", error);
|
|
95
95
|
return { done: true, value: void 0 };
|
|
96
96
|
}
|
|
97
97
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data_streams/stream_reader.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '../log.js';\nimport type { DataStream_Chunk } from '../proto/room_pb.js';\nimport { bigIntToNumber } from '../utils.js';\nimport type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';\n\nabstract class BaseStreamReader<T extends BaseStreamInfo> {\n protected reader: ReadableStream<DataStream_Chunk>;\n\n protected totalByteSize?: number;\n\n protected _info: T;\n\n protected bytesReceived: number;\n\n get info() {\n return this._info;\n }\n\n constructor(info: T, stream: ReadableStream<DataStream_Chunk>, totalByteSize?: number) {\n this.reader = stream;\n this.totalByteSize = totalByteSize;\n this._info = info;\n this.bytesReceived = 0;\n }\n\n protected abstract handleChunkReceived(chunk: DataStream_Chunk): void;\n\n onProgress?: (progress: number | undefined) => void;\n\n abstract readAll(): Promise<string | Array<Uint8Array>>;\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n this.bytesReceived += chunk.content!.byteLength;\n const currentProgress = this.totalByteSize\n ? this.bytesReceived / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n\n return {\n next: async (): Promise<IteratorResult<Uint8Array>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined as any };\n } else {\n this.handleChunkReceived(value);\n return { done: false, value: value.content! };\n }\n } catch (error) {\n log.error('error processing stream update', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<Uint8Array> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<Array<Uint8Array>> {\n const chunks: Set<Uint8Array> = new Set();\n for await (const chunk of this) {\n chunks.add(chunk);\n }\n return Array.from(chunks);\n }\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class TextStreamReader extends BaseStreamReader<TextStreamInfo> {\n private receivedChunks: Map<number, DataStream_Chunk>;\n\n /**\n * A TextStreamReader instance can be used as an AsyncIterator that returns the entire string\n * that has been received up to the current point in time.\n */\n constructor(\n info: TextStreamInfo,\n stream: ReadableStream<DataStream_Chunk>,\n totalChunkCount?: number,\n ) {\n super(info, stream, totalChunkCount);\n this.receivedChunks = new Map();\n }\n\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n const index = bigIntToNumber(chunk.chunkIndex!);\n const previousChunkAtIndex = this.receivedChunks.get(index!);\n if (previousChunkAtIndex && previousChunkAtIndex.version! > chunk.version!) {\n // we have a newer version already, dropping the old one\n return;\n }\n this.receivedChunks.set(index, chunk);\n const currentProgress = this.totalByteSize\n ? this.receivedChunks.size / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n /**\n * Async iterator implementation to allow usage of `for await...of` syntax.\n * Yields structured chunks from the stream.\n *\n */\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n const decoder = new TextDecoder();\n\n return {\n next: async (): Promise<IteratorResult<string>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined };\n } else {\n this.handleChunkReceived(value);\n return {\n done: false,\n value: decoder.decode(value.content!),\n };\n }\n } catch (error) {\n log.error('error processing stream update', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<string> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<string> {\n let finalString: string = '';\n for await (const chunk of this) {\n finalString += chunk;\n }\n return finalString;\n }\n}\n"],"mappings":"AAGA,SAAS,WAAW;AAEpB,SAAS,sBAAsB;AAG/B,MAAe,iBAA2C;AAAA,EASxD,IAAI,OAAO;AACT,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAY,MAAS,QAA0C,eAAwB;AACrF,SAAK,SAAS;AACd,SAAK,gBAAgB;AACrB,SAAK,QAAQ;AACb,SAAK,gBAAgB;AAAA,EACvB;AAOF;AAKO,MAAM,yBAAyB,iBAAiC;AAAA,EAC3D,oBAAoB,OAAyB;AAvCzD;AAwCI,SAAK,iBAAiB,MAAM,QAAS;AACrC,UAAM,kBAAkB,KAAK,gBACzB,KAAK,gBAAgB,KAAK,gBAC1B;AACJ,eAAK,eAAL,8BAAkB;AAAA,EACpB;AAAA,EAEA,CAAC,OAAO,aAAa,IAAI;AACvB,UAAM,SAAS,KAAK,OAAO,UAAU;AAErC,WAAO;AAAA,MACL,MAAM,YAAiD;AACrD,YAAI;AACF,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,cAAI,MAAM;AACR,mBAAO,EAAE,MAAM,MAAM,OAAO,OAAiB;AAAA,UAC/C,OAAO;AACL,iBAAK,oBAAoB,KAAK;AAC9B,mBAAO,EAAE,MAAM,OAAO,OAAO,MAAM,QAAS;AAAA,UAC9C;AAAA,QACF,SAAS,
|
|
1
|
+
{"version":3,"sources":["../../src/data_streams/stream_reader.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '../log.js';\nimport type { DataStream_Chunk } from '../proto/room_pb.js';\nimport { bigIntToNumber } from '../utils.js';\nimport type { BaseStreamInfo, ByteStreamInfo, TextStreamInfo } from './types.js';\n\nabstract class BaseStreamReader<T extends BaseStreamInfo> {\n protected reader: ReadableStream<DataStream_Chunk>;\n\n protected totalByteSize?: number;\n\n protected _info: T;\n\n protected bytesReceived: number;\n\n get info() {\n return this._info;\n }\n\n constructor(info: T, stream: ReadableStream<DataStream_Chunk>, totalByteSize?: number) {\n this.reader = stream;\n this.totalByteSize = totalByteSize;\n this._info = info;\n this.bytesReceived = 0;\n }\n\n protected abstract handleChunkReceived(chunk: DataStream_Chunk): void;\n\n onProgress?: (progress: number | undefined) => void;\n\n abstract readAll(): Promise<string | Array<Uint8Array>>;\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n this.bytesReceived += chunk.content!.byteLength;\n const currentProgress = this.totalByteSize\n ? this.bytesReceived / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n\n return {\n next: async (): Promise<IteratorResult<Uint8Array>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined as any };\n } else {\n this.handleChunkReceived(value);\n return { done: false, value: value.content! };\n }\n } catch (error: any) {\n log.error('error processing stream update: %s', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<Uint8Array> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<Array<Uint8Array>> {\n const chunks: Set<Uint8Array> = new Set();\n for await (const chunk of this) {\n chunks.add(chunk);\n }\n return Array.from(chunks);\n }\n}\n\n/**\n * A class to read chunks from a ReadableStream and provide them in a structured format.\n */\nexport class TextStreamReader extends BaseStreamReader<TextStreamInfo> {\n private receivedChunks: Map<number, DataStream_Chunk>;\n\n /**\n * A TextStreamReader instance can be used as an AsyncIterator that returns the entire string\n * that has been received up to the current point in time.\n */\n constructor(\n info: TextStreamInfo,\n stream: ReadableStream<DataStream_Chunk>,\n totalChunkCount?: number,\n ) {\n super(info, stream, totalChunkCount);\n this.receivedChunks = new Map();\n }\n\n protected handleChunkReceived(chunk: DataStream_Chunk) {\n const index = bigIntToNumber(chunk.chunkIndex!);\n const previousChunkAtIndex = this.receivedChunks.get(index!);\n if (previousChunkAtIndex && previousChunkAtIndex.version! > chunk.version!) {\n // we have a newer version already, dropping the old one\n return;\n }\n this.receivedChunks.set(index, chunk);\n const currentProgress = this.totalByteSize\n ? this.receivedChunks.size / this.totalByteSize\n : undefined;\n this.onProgress?.(currentProgress);\n }\n\n /**\n * Async iterator implementation to allow usage of `for await...of` syntax.\n * Yields structured chunks from the stream.\n *\n */\n [Symbol.asyncIterator]() {\n const reader = this.reader.getReader();\n const decoder = new TextDecoder();\n\n return {\n next: async (): Promise<IteratorResult<string>> => {\n try {\n const { done, value } = await reader.read();\n if (done) {\n return { done: true, value: undefined };\n } else {\n this.handleChunkReceived(value);\n return {\n done: false,\n value: decoder.decode(value.content!),\n };\n }\n } catch (error: any) {\n log.error('error processing stream update: %s', error);\n return { done: true, value: undefined };\n }\n },\n\n return(): IteratorResult<string> {\n reader.releaseLock();\n return { done: true, value: undefined };\n },\n };\n }\n\n async readAll(): Promise<string> {\n let finalString: string = '';\n for await (const chunk of this) {\n finalString += chunk;\n }\n return finalString;\n }\n}\n"],"mappings":"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","names":[]}
|