speechflow 2.0.2 → 2.0.3
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/CHANGELOG.md +9 -0
- package/etc/claude.md +1 -1
- package/package.json +4 -4
- package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-graph.js +4 -4
- package/speechflow-cli/dst/speechflow-main-graph.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main.js +1 -1
- package/speechflow-cli/dst/speechflow-main.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +6 -6
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js +2 -2
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-google.js +8 -8
- package/speechflow-cli/dst/speechflow-node-a2t-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +9 -9
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-google.js +3 -3
- package/speechflow-cli/dst/speechflow-node-t2a-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js +4 -4
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-format.js +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-format.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-opus.js +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-opus.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-summary.js +2 -2
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-exec.js +2 -2
- package/speechflow-cli/dst/speechflow-node-xio-exec.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-file.js +2 -2
- package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-vban.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-webrtc.js +1 -1
- package/speechflow-cli/dst/speechflow-util-audio.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-util-audio.js +10 -3
- package/speechflow-cli/dst/speechflow-util-audio.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-queue.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-stream.js +4 -5
- package/speechflow-cli/dst/speechflow-util-stream.js.map +1 -1
- package/speechflow-cli/etc/eslint.mjs +1 -3
- package/speechflow-cli/etc/oxlint.jsonc +2 -1
- package/speechflow-cli/etc/stx.conf +0 -1
- package/speechflow-cli/package.json +10 -13
- package/speechflow-cli/src/lib.d.ts +5 -1
- package/speechflow-cli/src/speechflow-main-api.ts +4 -4
- package/speechflow-cli/src/speechflow-main-cli.ts +1 -1
- package/speechflow-cli/src/speechflow-main-graph.ts +16 -16
- package/speechflow-cli/src/speechflow-main-nodes.ts +1 -1
- package/speechflow-cli/src/speechflow-main-status.ts +2 -2
- package/speechflow-cli/src/speechflow-main.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +3 -3
- package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +6 -6
- package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +2 -2
- package/speechflow-cli/src/speechflow-node-a2a-filler.ts +4 -4
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2a-mute.ts +2 -2
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise-wt.ts +2 -2
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +2 -2
- package/speechflow-cli/src/speechflow-node-a2t-google.ts +8 -8
- package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +9 -9
- package/speechflow-cli/src/speechflow-node-t2a-google.ts +3 -3
- package/speechflow-cli/src/speechflow-node-t2t-amazon.ts +4 -4
- package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +1 -1
- package/speechflow-cli/src/speechflow-node-t2t-format.ts +1 -1
- package/speechflow-cli/src/speechflow-node-t2t-google.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-modify.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-opus.ts +1 -1
- package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-summary.ts +2 -2
- package/speechflow-cli/src/speechflow-node-x2x-filter.ts +4 -4
- package/speechflow-cli/src/speechflow-node-xio-exec.ts +2 -2
- package/speechflow-cli/src/speechflow-node-xio-file.ts +2 -2
- package/speechflow-cli/src/speechflow-node-xio-vban.ts +4 -2
- package/speechflow-cli/src/speechflow-node-xio-webrtc.ts +1 -1
- package/speechflow-cli/src/speechflow-util-audio.ts +11 -3
- package/speechflow-cli/src/speechflow-util-stream.ts +4 -5
- package/speechflow-ui-db/dst/index.js +14 -14
- package/speechflow-ui-db/etc/oxlint.jsonc +137 -0
- package/speechflow-ui-db/etc/stx.conf +4 -3
- package/speechflow-ui-db/package.json +8 -5
- package/speechflow-ui-st/dst/index.js +32 -32
- package/speechflow-ui-st/etc/oxlint.jsonc +137 -0
- package/speechflow-ui-st/etc/stx.conf +4 -3
- package/speechflow-ui-st/package.json +8 -5
- package/speechflow-cli/dst/test.d.ts +0 -1
- package/speechflow-cli/dst/test.js +0 -18
- package/speechflow-cli/dst/test.js.map +0 -1
- package/speechflow-cli/etc/biome.jsonc +0 -46
- package/speechflow-ui-db/src/lib.d.ts +0 -9
- package/speechflow-ui-st/src/lib.d.ts +0 -9
|
@@ -43,7 +43,7 @@ class AsyncQueue<T> {
|
|
|
43
43
|
}
|
|
44
44
|
this.queue.length = 0
|
|
45
45
|
}
|
|
46
|
-
async *[Symbol.asyncIterator](): AsyncIterator<T> {
|
|
46
|
+
async * [Symbol.asyncIterator] (): AsyncIterator<T> {
|
|
47
47
|
while (true) {
|
|
48
48
|
if (this.queue.length > 0) {
|
|
49
49
|
const v = this.queue.shift()
|
|
@@ -128,7 +128,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
128
128
|
|
|
129
129
|
/* create an AudioStream for Amazon Transcribe */
|
|
130
130
|
const audioQueue = new AsyncQueue<Uint8Array>()
|
|
131
|
-
const audioStream = (async function *(q: AsyncQueue<Uint8Array>): AsyncIterable<AudioStream> {
|
|
131
|
+
const audioStream = (async function * (q: AsyncQueue<Uint8Array>): AsyncIterable<AudioStream> {
|
|
132
132
|
for await (const chunk of q) {
|
|
133
133
|
yield { AudioEvent: { AudioChunk: chunk } }
|
|
134
134
|
}
|
|
@@ -125,18 +125,18 @@ export default class SpeechFlowNodeA2TGoogle extends SpeechFlowNode {
|
|
|
125
125
|
const words: { word: string, start: Duration, end: Duration }[] = []
|
|
126
126
|
if (alternative.words && alternative.words.length > 0) {
|
|
127
127
|
for (const wordInfo of alternative.words) {
|
|
128
|
-
const wordStart = wordInfo.startTime
|
|
129
|
-
|
|
128
|
+
const wordStart = wordInfo.startTime ?
|
|
129
|
+
Duration.fromMillis(
|
|
130
130
|
(Number(wordInfo.startTime.seconds ?? 0) * 1000) +
|
|
131
131
|
(Number(wordInfo.startTime.nanos ?? 0) / 1000000)
|
|
132
|
-
).plus(this.timeZeroOffset)
|
|
133
|
-
|
|
134
|
-
const wordEnd = wordInfo.endTime
|
|
135
|
-
|
|
132
|
+
).plus(this.timeZeroOffset) :
|
|
133
|
+
Duration.fromMillis(0)
|
|
134
|
+
const wordEnd = wordInfo.endTime ?
|
|
135
|
+
Duration.fromMillis(
|
|
136
136
|
(Number(wordInfo.endTime.seconds ?? 0) * 1000) +
|
|
137
137
|
(Number(wordInfo.endTime.nanos ?? 0) / 1000000)
|
|
138
|
-
).plus(this.timeZeroOffset)
|
|
139
|
-
|
|
138
|
+
).plus(this.timeZeroOffset) :
|
|
139
|
+
Duration.fromMillis(0)
|
|
140
140
|
words.push({
|
|
141
141
|
word: wordInfo.word ?? "",
|
|
142
142
|
start: wordStart,
|
|
@@ -56,9 +56,9 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
56
56
|
try {
|
|
57
57
|
const elevenlabs = new ElevenLabs.ElevenLabsClient({ apiKey: this.params.key })
|
|
58
58
|
const subscription = await elevenlabs.user.subscription.get()
|
|
59
|
-
const percent = subscription.characterLimit > 0
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
const percent = subscription.characterLimit > 0 ?
|
|
60
|
+
subscription.characterCount / subscription.characterLimit :
|
|
61
|
+
0
|
|
62
62
|
return { usage: `${percent.toFixed(2)}%` }
|
|
63
63
|
}
|
|
64
64
|
catch (_error) {
|
|
@@ -103,15 +103,15 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
103
103
|
throw new Error(`invalid ElevenLabs voice "${this.params.voice}"`)
|
|
104
104
|
}
|
|
105
105
|
const labels = voice.labels ?? {}
|
|
106
|
-
const info = Object.keys(labels).length > 0
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
const info = Object.keys(labels).length > 0 ?
|
|
107
|
+
", " + Object.entries(labels).map(([ key, val ]) => `${key}: "${val}"`).join(", ") :
|
|
108
|
+
""
|
|
109
109
|
this.log("info", `selected voice: name: "${voice.name}"${info}`)
|
|
110
110
|
|
|
111
111
|
/* perform text-to-speech operation with Elevenlabs API */
|
|
112
|
-
const model = this.params.optimize === "quality"
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const model = this.params.optimize === "quality" ?
|
|
113
|
+
"eleven_turbo_v2_5" :
|
|
114
|
+
"eleven_flash_v2_5"
|
|
115
115
|
const speechStream = (text: string) => {
|
|
116
116
|
this.log("info", `ElevenLabs: send text "${text}"`)
|
|
117
117
|
return this.elevenlabs!.textToSpeech.convert(voice.voiceId, {
|
|
@@ -103,9 +103,9 @@ export default class SpeechFlowNodeT2AGoogle extends SpeechFlowNode {
|
|
|
103
103
|
throw new Error("no audio content returned from Google TTS")
|
|
104
104
|
|
|
105
105
|
/* convert response to buffer */
|
|
106
|
-
const buffer = Buffer.isBuffer(response.audioContent)
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
const buffer = Buffer.isBuffer(response.audioContent) ?
|
|
107
|
+
response.audioContent :
|
|
108
|
+
Buffer.from(response.audioContent)
|
|
109
109
|
this.log("info", `Google TTS: received audio (buffer length: ${buffer.byteLength})`)
|
|
110
110
|
|
|
111
111
|
/* resample from Google's sample rate to our standard rate */
|
|
@@ -91,9 +91,9 @@ export default class SpeechFlowNodeT2TAmazon extends SpeechFlowNode {
|
|
|
91
91
|
|
|
92
92
|
/* simple backoff for transient errors */
|
|
93
93
|
const retriable =
|
|
94
|
-
e?.name === "ThrottlingException"
|
|
95
|
-
e?.name === "ServiceUnavailableException"
|
|
96
|
-
e?.$retryable === true
|
|
94
|
+
e?.name === "ThrottlingException"
|
|
95
|
+
|| e?.name === "ServiceUnavailableException"
|
|
96
|
+
|| e?.$retryable === true
|
|
97
97
|
if (!retriable || attempt >= maxRetries)
|
|
98
98
|
break
|
|
99
99
|
const delayMs = Math.min(1000 * Math.pow(2, attempt - 1), 5000)
|
|
@@ -103,7 +103,7 @@ export default class SpeechFlowNodeT2TAmazon extends SpeechFlowNode {
|
|
|
103
103
|
throw util.ensureError(lastError)
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
/* establish a
|
|
106
|
+
/* establish a transform stream and connect it to AWS Translate */
|
|
107
107
|
this.stream = new Stream.Transform({
|
|
108
108
|
readableObjectMode: true,
|
|
109
109
|
writableObjectMode: true,
|
|
@@ -75,7 +75,7 @@ export default class SpeechFlowNodeT2TDeepL extends SpeechFlowNode {
|
|
|
75
75
|
return (result?.text ?? text)
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
/* establish a
|
|
78
|
+
/* establish a transform stream and connect it to DeepL translation */
|
|
79
79
|
this.stream = new Stream.Transform({
|
|
80
80
|
readableObjectMode: true,
|
|
81
81
|
writableObjectMode: true,
|
|
@@ -42,7 +42,7 @@ export default class SpeechFlowNodeT2TFormat extends SpeechFlowNode {
|
|
|
42
42
|
return text
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/* establish a
|
|
45
|
+
/* establish a transform stream and connect it to text formatting */
|
|
46
46
|
this.stream = new Stream.Transform({
|
|
47
47
|
readableObjectMode: true,
|
|
48
48
|
writableObjectMode: true,
|
|
@@ -85,7 +85,7 @@ export default class SpeechFlowNodeT2TGoogle extends SpeechFlowNode {
|
|
|
85
85
|
return response.translations?.[0]?.translatedText ?? text
|
|
86
86
|
})
|
|
87
87
|
|
|
88
|
-
/* establish a
|
|
88
|
+
/* establish a transform stream and connect it to Google Translate */
|
|
89
89
|
this.stream = new Stream.Transform({
|
|
90
90
|
readableObjectMode: true,
|
|
91
91
|
writableObjectMode: true,
|
|
@@ -129,4 +129,4 @@ export default class SpeechFlowNodeT2TGoogle extends SpeechFlowNode {
|
|
|
129
129
|
this.client = null
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
}
|
|
132
|
+
}
|
|
@@ -45,7 +45,7 @@ export default class SpeechFlowNodeT2TModify extends SpeechFlowNode {
|
|
|
45
45
|
const modify = (text: string): string =>
|
|
46
46
|
text.replace(regex, this.params.replace)
|
|
47
47
|
|
|
48
|
-
/* establish a
|
|
48
|
+
/* establish a transform stream and connect it to text modification */
|
|
49
49
|
this.stream = new Stream.Transform({
|
|
50
50
|
readableObjectMode: true,
|
|
51
51
|
writableObjectMode: true,
|
|
@@ -80,4 +80,4 @@ export default class SpeechFlowNodeT2TModify extends SpeechFlowNode {
|
|
|
80
80
|
this.stream = null
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
}
|
|
83
|
+
}
|
|
@@ -89,7 +89,7 @@ export default class SpeechFlowNodeT2TOPUS extends SpeechFlowNode {
|
|
|
89
89
|
return (single as Transformers.TranslationSingle).translation_text
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
/* establish a
|
|
92
|
+
/* establish a transform stream and connect it to Transformers */
|
|
93
93
|
this.stream = new Stream.Transform({
|
|
94
94
|
readableObjectMode: true,
|
|
95
95
|
writableObjectMode: true,
|
|
@@ -124,7 +124,7 @@ export default class SpeechFlowNodeT2TSubtitle extends SpeechFlowNode {
|
|
|
124
124
|
return output
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
/* establish a
|
|
127
|
+
/* establish a transform stream */
|
|
128
128
|
const self = this
|
|
129
129
|
let headerEmitted = false
|
|
130
130
|
this.stream = new Stream.Transform({
|
|
@@ -264,7 +264,7 @@ export default class SpeechFlowNodeT2TSubtitle extends SpeechFlowNode {
|
|
|
264
264
|
/* buffer for accumulating input */
|
|
265
265
|
let buffer = ""
|
|
266
266
|
|
|
267
|
-
/* establish a
|
|
267
|
+
/* establish a transform stream */
|
|
268
268
|
const self = this
|
|
269
269
|
this.stream = new Stream.Transform({
|
|
270
270
|
readableObjectMode: true,
|
|
@@ -168,7 +168,7 @@ export default class SpeechFlowNodeT2TSummary extends SpeechFlowNode {
|
|
|
168
168
|
/* check if we should generate a summary */
|
|
169
169
|
if (self.sentencesSinceLastSummary >= self.params.trigger) {
|
|
170
170
|
self.sentencesSinceLastSummary = 0
|
|
171
|
-
self.log("info",
|
|
171
|
+
self.log("info", "generating summary of accumulated text")
|
|
172
172
|
const textToSummarize = self.accumulatedText
|
|
173
173
|
self.accumulatedText = ""
|
|
174
174
|
summarize(textToSummarize).then((summary) => {
|
|
@@ -188,7 +188,7 @@ export default class SpeechFlowNodeT2TSummary extends SpeechFlowNode {
|
|
|
188
188
|
/* generate final summary if there is accumulated text */
|
|
189
189
|
if (self.accumulatedText.length > 0 && self.sentencesSinceLastSummary > 0) {
|
|
190
190
|
self.sentencesSinceLastSummary = 0
|
|
191
|
-
self.log("info",
|
|
191
|
+
self.log("info", "generating final summary of accumulated text")
|
|
192
192
|
const textToSummarize = self.accumulatedText
|
|
193
193
|
self.accumulatedText = ""
|
|
194
194
|
summarize(textToSummarize).then((summary) => {
|
|
@@ -83,10 +83,10 @@ export default class SpeechFlowNodeX2XFilter extends SpeechFlowNode {
|
|
|
83
83
|
const num2 = coerceNum(val2)
|
|
84
84
|
return (
|
|
85
85
|
op === "<" ? (num1 < num2) :
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
op === "<=" ? (num1 <= num2) :
|
|
87
|
+
op === ">=" ? (num1 >= num2) :
|
|
88
|
+
op === ">" ? (num1 > num2) :
|
|
89
|
+
false
|
|
90
90
|
)
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -151,8 +151,8 @@ export default class SpeechFlowNodeXIOExec extends SpeechFlowNode {
|
|
|
151
151
|
/* terminate subprocess */
|
|
152
152
|
if (this.subprocess !== null) {
|
|
153
153
|
/* gracefully end stdin if in write or read/write mode */
|
|
154
|
-
if ((this.params.mode === "w" || this.params.mode === "rw") && this.subprocess.stdin
|
|
155
|
-
!this.subprocess.stdin.destroyed && !this.subprocess.stdin.writableEnded) {
|
|
154
|
+
if ((this.params.mode === "w" || this.params.mode === "rw") && this.subprocess.stdin
|
|
155
|
+
&& !this.subprocess.stdin.destroyed && !this.subprocess.stdin.writableEnded) {
|
|
156
156
|
await Promise.race([
|
|
157
157
|
new Promise<void>((resolve, reject) => {
|
|
158
158
|
this.subprocess!.stdin!.end((err?: Error) => {
|
|
@@ -197,8 +197,8 @@ export default class SpeechFlowNodeXIOFile extends SpeechFlowNode {
|
|
|
197
197
|
else {
|
|
198
198
|
/* for stdio streams, just end without destroying */
|
|
199
199
|
const stream = this.stream
|
|
200
|
-
if ((stream instanceof Stream.Writable || stream instanceof Stream.Duplex)
|
|
201
|
-
(!stream.writableEnded && !stream.destroyed)) {
|
|
200
|
+
if ((stream instanceof Stream.Writable || stream instanceof Stream.Duplex)
|
|
201
|
+
&& (!stream.writableEnded && !stream.destroyed)) {
|
|
202
202
|
await Promise.race([
|
|
203
203
|
new Promise<void>((resolve, reject) => {
|
|
204
204
|
stream.end((err?: Error) => {
|
|
@@ -9,8 +9,10 @@ import Stream from "node:stream"
|
|
|
9
9
|
|
|
10
10
|
/* external dependencies */
|
|
11
11
|
import { DateTime } from "luxon"
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
VBANServer, VBANAudioPacket,
|
|
14
|
+
EBitsResolutions, ECodecs
|
|
15
|
+
} from "vban"
|
|
14
16
|
|
|
15
17
|
/* internal dependencies */
|
|
16
18
|
import SpeechFlowNode, { SpeechFlowChunk } from "./speechflow-node"
|
|
@@ -306,7 +306,7 @@ export default class SpeechFlowNodeXIOWebRTC extends SpeechFlowNode {
|
|
|
306
306
|
pc.ontrack = (event: { track: MediaStreamTrack }) => {
|
|
307
307
|
const track = event.track
|
|
308
308
|
if (track.kind === "audio") {
|
|
309
|
-
this.log("info",
|
|
309
|
+
this.log("info", "WebRTC audio track received from publisher")
|
|
310
310
|
|
|
311
311
|
/* subscribe to incoming RTP packets */
|
|
312
312
|
track.onReceiveRtp.subscribe((rtpPacket: RtpPacket) => {
|
|
@@ -168,10 +168,12 @@ export function updateEnvelopeForChannel (
|
|
|
168
168
|
return Math.sqrt(Math.max(currentEnv, 1e-12))
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
/* helper
|
|
171
|
+
/* helper function for linear to decibel conversion */
|
|
172
172
|
export function lin2dB (x: number): number {
|
|
173
173
|
return 20 * Math.log10(Math.max(x, 1e-12))
|
|
174
174
|
}
|
|
175
|
+
|
|
176
|
+
/* helper function for decibel to linear conversion */
|
|
175
177
|
export function dB2lin (db: number): number {
|
|
176
178
|
return Math.pow(10, db / 20)
|
|
177
179
|
}
|
|
@@ -187,6 +189,7 @@ export class WebAudio {
|
|
|
187
189
|
reject: (error: Error) => void
|
|
188
190
|
timeout: ReturnType<typeof setTimeout>
|
|
189
191
|
}>()
|
|
192
|
+
private captureListener: ((event: MessageEvent) => void) | null = null
|
|
190
193
|
|
|
191
194
|
/* construct object */
|
|
192
195
|
constructor (
|
|
@@ -222,7 +225,7 @@ export class WebAudio {
|
|
|
222
225
|
numberOfInputs: 1,
|
|
223
226
|
numberOfOutputs: 0
|
|
224
227
|
})
|
|
225
|
-
this.
|
|
228
|
+
this.captureListener = (event) => {
|
|
226
229
|
const { type, chunkId, data } = event.data ?? {}
|
|
227
230
|
if (type === "capture-complete") {
|
|
228
231
|
const promise = this.pendingPromises.get(chunkId)
|
|
@@ -235,7 +238,8 @@ export class WebAudio {
|
|
|
235
238
|
promise.resolve(int16Data)
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
|
-
}
|
|
241
|
+
}
|
|
242
|
+
this.captureNode.port.addEventListener("message", this.captureListener)
|
|
239
243
|
|
|
240
244
|
/* start ports */
|
|
241
245
|
this.sourceNode.port.start()
|
|
@@ -302,6 +306,10 @@ export class WebAudio {
|
|
|
302
306
|
this.sourceNode = null
|
|
303
307
|
}
|
|
304
308
|
if (this.captureNode !== null) {
|
|
309
|
+
if (this.captureListener !== null) {
|
|
310
|
+
this.captureNode.port.removeEventListener("message", this.captureListener)
|
|
311
|
+
this.captureListener = null
|
|
312
|
+
}
|
|
305
313
|
this.captureNode.disconnect()
|
|
306
314
|
this.captureNode = null
|
|
307
315
|
}
|
|
@@ -208,11 +208,10 @@ export async function destroyStream (
|
|
|
208
208
|
stream: Stream.Readable | Stream.Writable | Stream.Duplex | Stream.Transform
|
|
209
209
|
) {
|
|
210
210
|
/* signal the end for a writable stream */
|
|
211
|
-
if ((stream instanceof Stream.Duplex
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
(!stream.writableEnded &&
|
|
215
|
-
!stream.destroyed ) )
|
|
211
|
+
if (( stream instanceof Stream.Duplex
|
|
212
|
+
|| stream instanceof Stream.Transform
|
|
213
|
+
|| stream instanceof Stream.Writable )
|
|
214
|
+
&& (!stream.writableEnded && !stream.destroyed))
|
|
216
215
|
await Promise.race([
|
|
217
216
|
new Promise<void>((resolve) => {
|
|
218
217
|
stream.end(() => { resolve() })
|