@burdenoff/fe-libs 2026.1013.9 → 2026.1013.10
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/shared/assistant/index.d.ts +1 -0
- package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +90 -71
- package/dist/shared/assistant/speech/pieceSink.d.ts +43 -0
- package/dist/shared/assistant/speech/pieceSink.js +84 -0
- package/dist/shared/assistant/speech/types.d.ts +73 -0
- package/dist/shared/assistant/speech/types.js +4 -0
- package/dist/shared-assistant.js +240 -238
- package/package.json +1 -1
|
@@ -44,6 +44,7 @@ export * from './speech/browserSpeechEngine';
|
|
|
44
44
|
export * from './speech/hostedTtsSpeechEngine';
|
|
45
45
|
export * from './speech/routingSpeechEngine';
|
|
46
46
|
export * from './speech/hostedVoiceCatalogue';
|
|
47
|
+
export * from './speech/pieceSink';
|
|
47
48
|
export * from './speech/speechFeed';
|
|
48
49
|
export * from './voice/useVoiceInput';
|
|
49
50
|
export * from './voice/voiceStageState';
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { tapPlaybackElement as e } from "../voice/handsfree/playbackReference.js";
|
|
2
2
|
import { HOSTED_TTS_TIER as t, HOSTED_VOICES as n, hostedLocaleFor as r } from "./hostedVoiceCatalogue.js";
|
|
3
3
|
import { buildRequest as i, classifyHttpFailure as a, decodeAudioResponse as o, disableDurationMs as s, shouldDisableEngine as c, speakableChunks as l } from "./hostedTtsProtocol.js";
|
|
4
|
+
import { createPieceSink as u } from "./pieceSink.js";
|
|
4
5
|
//#region src/shared/assistant/speech/hostedTtsSpeechEngine.ts
|
|
5
|
-
function
|
|
6
|
+
function d(e) {
|
|
6
7
|
let t = Object.entries(e).map(([e, t]) => `${e.toLowerCase()}:${t}`).sort().join("\n"), n = 5381;
|
|
7
8
|
for (let e = 0; e < t.length; e += 1) n = (n << 5) + n + t.charCodeAt(e) | 0;
|
|
8
9
|
return `${t.length}:${n >>> 0}`;
|
|
9
10
|
}
|
|
10
|
-
var
|
|
11
|
+
var f = new Set([
|
|
11
12
|
429,
|
|
12
13
|
502,
|
|
13
14
|
503,
|
|
14
15
|
504
|
|
15
|
-
]),
|
|
16
|
-
function
|
|
16
|
+
]), p = 3, m = 400, h = 2e3;
|
|
17
|
+
function g(e, t) {
|
|
17
18
|
let n = e === null ? NaN : Number(e);
|
|
18
|
-
return Math.min(Number.isFinite(n) && n >= 0 ? n * 1e3 :
|
|
19
|
+
return Math.min(Number.isFinite(n) && n >= 0 ? n * 1e3 : m * 2 ** (t - 1), h);
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function _(e, t) {
|
|
21
22
|
return new Promise((n) => {
|
|
22
23
|
if (t.aborted) {
|
|
23
24
|
n();
|
|
@@ -32,44 +33,44 @@ function g(e, t) {
|
|
|
32
33
|
t.addEventListener("abort", i, { once: !0 });
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
|
-
function
|
|
36
|
-
let
|
|
36
|
+
function v(m) {
|
|
37
|
+
let h = m.fetchImpl ?? ((...e) => fetch(...e)), v = m.now ?? (() => Date.now()), y = null, b = null, x = 0, S = null, C = null, w = 0, T = null, E = null, D = () => {
|
|
37
38
|
try {
|
|
38
|
-
return
|
|
39
|
+
return m.getHeaders?.() ?? {};
|
|
39
40
|
} catch {
|
|
40
41
|
return {};
|
|
41
42
|
}
|
|
42
|
-
},
|
|
43
|
-
for (let e of [...
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let e =
|
|
43
|
+
}, O = () => v() >= w ? !1 : E === null ? !0 : d(D()) === E, k = /* @__PURE__ */ new Set(), A = () => {
|
|
44
|
+
for (let e of [...k]) e();
|
|
45
|
+
}, j = () => {
|
|
46
|
+
T !== null && clearTimeout(T), T = null;
|
|
47
|
+
}, M = (e) => {
|
|
48
|
+
j(), T = setTimeout(() => {
|
|
49
|
+
T = null;
|
|
50
|
+
let e = w - v();
|
|
50
51
|
if (e > 0) {
|
|
51
|
-
|
|
52
|
+
M(e);
|
|
52
53
|
return;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
A();
|
|
55
56
|
}, e);
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
if (
|
|
62
|
-
|
|
57
|
+
}, N = (e, t) => {
|
|
58
|
+
w = v() + e, E = t, M(e), A();
|
|
59
|
+
}, P = () => {
|
|
60
|
+
b &&= (URL.revokeObjectURL(b), null);
|
|
61
|
+
}, F = () => {
|
|
62
|
+
if (y) {
|
|
63
|
+
y.onended = null, y.onerror = null;
|
|
63
64
|
try {
|
|
64
|
-
|
|
65
|
+
y.pause();
|
|
65
66
|
} catch {}
|
|
66
|
-
|
|
67
|
+
y = null;
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
+
P();
|
|
69
70
|
};
|
|
70
|
-
async function
|
|
71
|
-
let c = i(e, r(n.lang) ?? n.lang, t, n.voice?.name ?? null, n.rate), l =
|
|
72
|
-
for (let e = 1;
|
|
71
|
+
async function I(e, n, s) {
|
|
72
|
+
let c = i(e, r(n.lang) ?? n.lang, t, n.voice?.name ?? null, n.rate), l = m.getHeaders?.() ?? {}, u;
|
|
73
|
+
for (let e = 1; u = await h(m.endpoint, {
|
|
73
74
|
method: "POST",
|
|
74
75
|
signal: s,
|
|
75
76
|
headers: {
|
|
@@ -77,42 +78,42 @@ function _(p) {
|
|
|
77
78
|
...l
|
|
78
79
|
},
|
|
79
80
|
body: JSON.stringify(c)
|
|
80
|
-
}), !
|
|
81
|
-
if (!(
|
|
82
|
-
let e = /* @__PURE__ */ Error(`hosted tts ${
|
|
83
|
-
throw e.reason = a(
|
|
81
|
+
}), !u.ok; e += 1) {
|
|
82
|
+
if (!(f.has(u.status) && e < p && !s.aborted)) {
|
|
83
|
+
let e = /* @__PURE__ */ Error(`hosted tts ${u.status}`);
|
|
84
|
+
throw e.reason = a(u.status), e.headers = d(l), e;
|
|
84
85
|
}
|
|
85
|
-
await g(
|
|
86
|
+
await _(g(u.headers.get("retry-after"), e), s);
|
|
86
87
|
}
|
|
87
|
-
let v =
|
|
88
|
+
let v = u.headers.get("content-type"), y = o(v, v?.includes("json") ? await u.json() : await u.arrayBuffer());
|
|
88
89
|
if (!y) {
|
|
89
90
|
let e = /* @__PURE__ */ Error("hosted tts returned no audio");
|
|
90
91
|
throw e.reason = "unknown", e;
|
|
91
92
|
}
|
|
92
93
|
return y;
|
|
93
94
|
}
|
|
94
|
-
function
|
|
95
|
+
function L(t, n, r) {
|
|
95
96
|
return new Promise((i, a) => {
|
|
96
|
-
if (n !==
|
|
97
|
+
if (n !== x) {
|
|
97
98
|
i();
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
let o = new Blob([t.slice().buffer], { type: "audio/mpeg" });
|
|
101
|
-
|
|
102
|
-
let s = new Audio(
|
|
103
|
-
e(s),
|
|
104
|
-
n ===
|
|
102
|
+
P(), b = URL.createObjectURL(o);
|
|
103
|
+
let s = new Audio(b);
|
|
104
|
+
e(s), y = s, s.onended = () => {
|
|
105
|
+
n === x && i();
|
|
105
106
|
}, s.onerror = () => {
|
|
106
|
-
if (n !==
|
|
107
|
+
if (n !== x) {
|
|
107
108
|
i();
|
|
108
109
|
return;
|
|
109
110
|
}
|
|
110
111
|
let e = /* @__PURE__ */ Error("audio playback failed");
|
|
111
112
|
e.reason = "unknown", a(e);
|
|
112
113
|
}, s.play().then(() => {
|
|
113
|
-
n ===
|
|
114
|
+
n === x && r?.();
|
|
114
115
|
}, (e) => {
|
|
115
|
-
if (n !==
|
|
116
|
+
if (n !== x) {
|
|
116
117
|
i();
|
|
117
118
|
return;
|
|
118
119
|
}
|
|
@@ -124,14 +125,14 @@ function _(p) {
|
|
|
124
125
|
return {
|
|
125
126
|
id: "hosted-tts",
|
|
126
127
|
isSupported() {
|
|
127
|
-
return
|
|
128
|
+
return O() ? !1 : typeof window < "u" && typeof window.Audio == "function" && typeof fetch == "function";
|
|
128
129
|
},
|
|
129
130
|
listVoices() {
|
|
130
|
-
return
|
|
131
|
+
return O() ? [] : [...n];
|
|
131
132
|
},
|
|
132
133
|
subscribeVoices(e) {
|
|
133
|
-
return
|
|
134
|
-
|
|
134
|
+
return k.add(e), () => {
|
|
135
|
+
k.delete(e);
|
|
135
136
|
};
|
|
136
137
|
},
|
|
137
138
|
speak(e, t, n = {}) {
|
|
@@ -140,43 +141,61 @@ function _(p) {
|
|
|
140
141
|
n.onEnd?.();
|
|
141
142
|
return;
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
-
let i =
|
|
145
|
-
|
|
144
|
+
x += 1;
|
|
145
|
+
let i = x;
|
|
146
|
+
F(), C?.cancel();
|
|
146
147
|
let a = new AbortController();
|
|
147
|
-
|
|
148
|
-
let o = !1,
|
|
148
|
+
S = a;
|
|
149
|
+
let o = !1, d = () => {
|
|
149
150
|
o || (o = !0, n.onStart?.());
|
|
150
|
-
},
|
|
151
|
-
let n =
|
|
151
|
+
}, f = (e) => {
|
|
152
|
+
let n = I(e, t, a.signal);
|
|
152
153
|
return n.catch(() => {}), n;
|
|
153
|
-
}
|
|
154
|
-
|
|
154
|
+
}, p = t.audioOutput ? u(t.audioOutput, {
|
|
155
|
+
play: (e) => L(e, i, d),
|
|
156
|
+
isCurrent: () => i === x,
|
|
157
|
+
onChunkStart: (e) => n.onChunkStart?.(e),
|
|
158
|
+
onStart: d
|
|
159
|
+
}) : null;
|
|
160
|
+
C = p, (async () => {
|
|
155
161
|
try {
|
|
156
|
-
let e =
|
|
162
|
+
let e = f(r[0]);
|
|
157
163
|
for (let t = 0; t < r.length; t += 1) {
|
|
158
|
-
if (i !==
|
|
164
|
+
if (i !== x) return;
|
|
159
165
|
let a = await e;
|
|
160
|
-
if (i !==
|
|
166
|
+
if (i !== x) return;
|
|
161
167
|
let o = r[t + 1];
|
|
162
|
-
o !== void 0 && (e =
|
|
168
|
+
if (o !== void 0 && (e = f(o)), p) {
|
|
169
|
+
await p.write(a);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
n.onChunkStart?.(t), await L(a, i, d);
|
|
163
173
|
}
|
|
164
|
-
|
|
174
|
+
if (p) {
|
|
175
|
+
let e = await p.drain();
|
|
176
|
+
if (i !== x) return;
|
|
177
|
+
if (!e) throw Object.assign(/* @__PURE__ */ Error("audio output did not finish"), { reason: "unknown" });
|
|
178
|
+
}
|
|
179
|
+
i === x && n.onEnd?.();
|
|
165
180
|
} catch (e) {
|
|
166
|
-
if (a.abort(), i !==
|
|
167
|
-
|
|
181
|
+
if (a.abort(), i !== x) return;
|
|
182
|
+
if (p) {
|
|
183
|
+
if (await p.drain().catch(() => !1), i !== x) return;
|
|
184
|
+
p.cancel();
|
|
185
|
+
}
|
|
186
|
+
x += 1, F();
|
|
168
187
|
let t = e?.reason;
|
|
169
|
-
c(t, e?.transient === !0) &&
|
|
188
|
+
c(t, e?.transient === !0) && N(s(t), t === "not-allowed" ? e.headers ?? null : null), n.onError?.(t === "not-allowed" || t === "unsupported" || t === "cancelled" ? t : "unknown");
|
|
170
189
|
}
|
|
171
190
|
})();
|
|
172
191
|
},
|
|
173
192
|
headersChanged() {
|
|
174
|
-
|
|
193
|
+
v() >= w || E === null || O() || (w = 0, E = null, j(), A());
|
|
175
194
|
},
|
|
176
195
|
cancel() {
|
|
177
|
-
|
|
196
|
+
x += 1, S?.abort(), S = null, F(), C?.cancel(), C = null;
|
|
178
197
|
}
|
|
179
198
|
};
|
|
180
199
|
}
|
|
181
200
|
//#endregion
|
|
182
|
-
export {
|
|
201
|
+
export { v as createHostedTtsEngine, g as retryDelayMs };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { SpeechAudioOutput } from './types';
|
|
2
|
+
/** @internal What the sink needs from the reply it belongs to. */
|
|
3
|
+
export interface PieceSinkReply {
|
|
4
|
+
/** Plays one piece on the speakers and resolves when it has finished: the engine's own `play`. */
|
|
5
|
+
play(bytes: Uint8Array): Promise<void>;
|
|
6
|
+
/** False once the reply was cancelled or replaced: nothing more is played. */
|
|
7
|
+
isCurrent(): boolean;
|
|
8
|
+
/** Piece `index` begins: the live caption's sync signal. */
|
|
9
|
+
onChunkStart(index: number): void;
|
|
10
|
+
/** The reply's first sound (the engine announces it once per reply). */
|
|
11
|
+
onStart(): void;
|
|
12
|
+
}
|
|
13
|
+
/** @internal The engine's side of one reply's audio output. */
|
|
14
|
+
export interface PieceSink {
|
|
15
|
+
/**
|
|
16
|
+
* Hand over the reply's next piece. Pieces are numbered 0, 1, 2… by ONE
|
|
17
|
+
* counter for the whole reply: a queue's count continues across appends and
|
|
18
|
+
* across drains, and a retracted number is never given again. Resolves when
|
|
19
|
+
* the next piece may follow; rejects as `drain` does once the speakers fail.
|
|
20
|
+
*/
|
|
21
|
+
write(bytes: Uint8Array): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Resolves once everything written so far has finished playing: `true`, or
|
|
24
|
+
* `false` when the output FAILED after every piece had begun, so the end was
|
|
25
|
+
* never confirmed (a leave is not a failure: `true`). Callable any number of
|
|
26
|
+
* times; writing may go on after it, even while it is pending (a piece written
|
|
27
|
+
* meanwhile is not part of it). Never rejects with the output's reason, only
|
|
28
|
+
* with the speakers' own failure, which the engine reports as it always has.
|
|
29
|
+
* Once the speakers have failed, every later or queued `write` and `drain`
|
|
30
|
+
* rejects with that same failure until `cancel()`: nothing more plays, and
|
|
31
|
+
* nothing is confirmed.
|
|
32
|
+
*/
|
|
33
|
+
drain(): Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Withdraw every piece from `fromIndex` on that has not begun, on the output
|
|
36
|
+
* and in the record a failure replays from; the one playing finishes.
|
|
37
|
+
*/
|
|
38
|
+
retract(fromIndex: number): void;
|
|
39
|
+
/** The hard stop: silence the output and drop everything. Nothing is replayed. */
|
|
40
|
+
cancel(): void;
|
|
41
|
+
}
|
|
42
|
+
/** @internal One reply's piece sink, playing on `output` until it fails or leaves. */
|
|
43
|
+
export declare function createPieceSink(output: SpeechAudioOutput, reply: PieceSinkReply): PieceSink;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { SPEECH_OUTPUT_LEFT as e } from "./types.js";
|
|
2
|
+
//#region src/shared/assistant/speech/pieceSink.ts
|
|
3
|
+
var t = (t) => t?.reason === e;
|
|
4
|
+
function n(e, n) {
|
|
5
|
+
let r = e, i = !1, a = 0, o = /* @__PURE__ */ new Map(), s = () => !i && n.isCurrent(), c = () => {
|
|
6
|
+
let e = r;
|
|
7
|
+
r = null;
|
|
8
|
+
try {
|
|
9
|
+
e?.cancel();
|
|
10
|
+
} catch {}
|
|
11
|
+
}, l = (e, t) => () => {
|
|
12
|
+
if (!(r !== e || !s() || !o.has(t))) {
|
|
13
|
+
for (let e of o.keys()) {
|
|
14
|
+
if (e > t) break;
|
|
15
|
+
o.delete(e);
|
|
16
|
+
}
|
|
17
|
+
n.onChunkStart(t), n.onStart();
|
|
18
|
+
}
|
|
19
|
+
}, u = !1, d = async () => {
|
|
20
|
+
for (let [e, t] of o) {
|
|
21
|
+
if (!s()) return;
|
|
22
|
+
o.delete(e), u = !0, n.onChunkStart(e);
|
|
23
|
+
try {
|
|
24
|
+
await n.play(t);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
throw o.clear(), e;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}, f = Promise.resolve(), p = () => {
|
|
30
|
+
if (!s()) return Promise.resolve();
|
|
31
|
+
let e = f.then(d);
|
|
32
|
+
return f = e, e;
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
async write(e) {
|
|
36
|
+
let t = a;
|
|
37
|
+
if (a += 1, !s()) return;
|
|
38
|
+
o.set(t, e);
|
|
39
|
+
let n = r;
|
|
40
|
+
if (n) try {
|
|
41
|
+
await n.write(e, t, l(n, t));
|
|
42
|
+
} catch {
|
|
43
|
+
if (!s()) return;
|
|
44
|
+
r === n && c();
|
|
45
|
+
}
|
|
46
|
+
r === null && await p();
|
|
47
|
+
},
|
|
48
|
+
async drain() {
|
|
49
|
+
let e = r;
|
|
50
|
+
if (e && s()) {
|
|
51
|
+
let n = a;
|
|
52
|
+
try {
|
|
53
|
+
if (await e.drain(), r === e) {
|
|
54
|
+
for (let e of o.keys()) {
|
|
55
|
+
if (e >= n) break;
|
|
56
|
+
o.delete(e);
|
|
57
|
+
}
|
|
58
|
+
return !0;
|
|
59
|
+
}
|
|
60
|
+
} catch (n) {
|
|
61
|
+
if (!s()) return !0;
|
|
62
|
+
let i = t(n) || o.size > 0;
|
|
63
|
+
return r === e && c(), await p(), i || u;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return await p(), !0;
|
|
67
|
+
},
|
|
68
|
+
retract(e) {
|
|
69
|
+
if (!s()) return;
|
|
70
|
+
let t = r;
|
|
71
|
+
if (t) try {
|
|
72
|
+
t.retract(e);
|
|
73
|
+
} catch {
|
|
74
|
+
r === t && c();
|
|
75
|
+
}
|
|
76
|
+
for (let t of o.keys()) t >= e && o.delete(t);
|
|
77
|
+
},
|
|
78
|
+
cancel() {
|
|
79
|
+
i = !0, o.clear(), c();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { n as createPieceSink };
|
|
@@ -17,7 +17,80 @@ export interface SpeechSpeakOptions {
|
|
|
17
17
|
* heard (BOFF-7283). Omitted means fallback is allowed.
|
|
18
18
|
*/
|
|
19
19
|
fallback?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Play this reply's hosted audio HERE instead of on the speakers: the
|
|
22
|
+
* optional live avatar (BOFF-8822). Attached per reply by the panel that
|
|
23
|
+
* shows the avatar, so no other caller of the shared engine can reach it.
|
|
24
|
+
* An engine with no audio data to hand over (the device voice) ignores it.
|
|
25
|
+
*
|
|
26
|
+
* It belongs to the whole reply: one output, one piece count and one hard
|
|
27
|
+
* stop, whether the reply is one `speak()` or a queue that grows by appends.
|
|
28
|
+
*/
|
|
29
|
+
audioOutput?: SpeechAudioOutput;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Somewhere other than the speakers to play a reply's hosted audio
|
|
33
|
+
* (BOFF-8822).
|
|
34
|
+
*
|
|
35
|
+
* ★★ The hosted engine keeps everything else: the request (voice, language,
|
|
36
|
+
* rate), the retries, the one-piece prefetch, the refusal latch, `cancel()`.
|
|
37
|
+
* Each piece is synthesised ONCE. If the output fails, the pieces it never
|
|
38
|
+
* began play on the speakers from the bytes already fetched, so falling back
|
|
39
|
+
* never synthesises anything twice, and an output's failure never latches the
|
|
40
|
+
* engine off.
|
|
41
|
+
*
|
|
42
|
+
* ★ Leaving is not stopping. When the output stops being the reply's
|
|
43
|
+
* destination while the reply goes on (the user switched the avatar off), it
|
|
44
|
+
* rejects the pending `write` or `drain` (or the next one, if none is pending)
|
|
45
|
+
* and every later one with an error whose `reason` is `SPEECH_OUTPUT_LEFT`. The
|
|
46
|
+
* rest of the reply then plays on the speakers, exactly as after a failure, and
|
|
47
|
+
* still ends with `onEnd`. Switching it off never goes through the engine's
|
|
48
|
+
* `cancel()`, which silences the reply, nor through `retract()`.
|
|
49
|
+
*
|
|
50
|
+
* One object serves exactly one reply: attach a fresh one to each, so neither
|
|
51
|
+
* a leave nor the hard stop carries over to the next reply.
|
|
52
|
+
*/
|
|
53
|
+
export interface SpeechAudioOutput {
|
|
54
|
+
/**
|
|
55
|
+
* Take piece `index` (the bytes the proxy returned). `index` counts the
|
|
56
|
+
* reply's pieces from 0 with ONE counter for the whole reply: for a queue it
|
|
57
|
+
* continues across appends, and a retracted number is never given again.
|
|
58
|
+
*
|
|
59
|
+
* Resolve when the next piece may follow: once this one is queued, pieces
|
|
60
|
+
* play back to back; resolving when it BEGINS keeps synthesis one piece
|
|
61
|
+
* ahead, as on the speakers. Call `began()` when its sound begins, and,
|
|
62
|
+
* before rejecting, for any piece that MAY have been heard: the speakers
|
|
63
|
+
* resume after the last piece that began, so nothing is heard twice. A piece
|
|
64
|
+
* retracted before it began resolves its `write` without `began()`. Writing
|
|
65
|
+
* may go on after a `drain()`, until `cancel()` or the reply's end.
|
|
66
|
+
*/
|
|
67
|
+
write(bytes: Uint8Array, index: number, began: () => void): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Resolve once everything written SO FAR has finished playing; reject as
|
|
70
|
+
* `write` does. Callable more than once: a queue may drain when its speech
|
|
71
|
+
* pauses and write again afterwards, even before that drain settles (a piece
|
|
72
|
+
* written meanwhile is not part of it). The reply's last drain follows its
|
|
73
|
+
* end and its last write.
|
|
74
|
+
*/
|
|
75
|
+
drain(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Drop every piece with `index >= fromIndex` that has not begun; the piece
|
|
78
|
+
* playing, if any, finishes. Call `began()` first for any of them that MAY
|
|
79
|
+
* have been heard: it is then the one playing, and stays. Queued speech is
|
|
80
|
+
* withdrawn this way; `cancel()` remains the hard stop.
|
|
81
|
+
*/
|
|
82
|
+
retract(fromIndex: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* The hard stop (a stop, a new reply, a failure): silence at once and drop
|
|
85
|
+
* everything queued. Pending `write`/`drain` calls still settle, either way.
|
|
86
|
+
*/
|
|
87
|
+
cancel(): void;
|
|
20
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* The `reason` a `SpeechAudioOutput` rejects with once it has LEFT the reply
|
|
91
|
+
* (switched off while the reply goes on). Any other rejection is a failure.
|
|
92
|
+
*/
|
|
93
|
+
export declare const SPEECH_OUTPUT_LEFT = "left";
|
|
21
94
|
/**
|
|
22
95
|
* Why playback stopped. `cancelled` is not a failure: it is what every queued
|
|
23
96
|
* utterance reports when we deliberately cancel (new playback, panel close,
|